G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsCombinatorics.h
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsCore/gsLinearAlgebra.h>
17 #include <gsCore/gsMath.h>
18 
19 namespace gismo
20 {
21 
27 // \ingroup Utils
28 // could also be in Utils, but doxygen allows only one group for free functions
29 inline unsigned factorial( unsigned n)
30 {
31  static const unsigned precomputed[]= {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600};
32  GISMO_ASSERT(n < util::size(precomputed), "Overflow when computing factorial.");
33  return precomputed[n];
34 }
35 
36 /*
37 // \brief Returns the factorial of \a n
38 // Remember that factorial grow too fast and only n! with n<=21 can
39 // be stored in a 64bit that is an unsigned long long. \ingroup
40 // combinatorics
41 inline unsigned long long factorial( unsigned long long n)
42 {
43 static const unsigned long long precomputed[]= {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000 };
44 GISMO_ASSERT(n < util::size(precomputed), "Overflow when computing factorial.");
45 return precomputed[n];
46 }
47 */
48 
66 // \ingroup Utils
67 // Note: could also be in Utils, but doxygen allows only one group for free functions
68 template <typename Z>
69 inline Z binomial(const Z n, const Z r)
70 {
71  GISMO_ASSERT(r>=0, "binomial coefficient (n,r) exists only for n,r positive");
72  //GISMO_ASSERT(n>=r, "binomial coefficient (n,r) exists only for n,r such that n>=r");
73 
74  const Z diff = math::min( n-r, r );
75  int result = 1;
76  for (Z i=0;i < diff;)
77  {
78  result *= n-i;
79  result /= ++i;
80  }
81  return result;
82 }
83 
94 //\ingroup Utils
95 inline void binomial_into( unsigned n, gsVector<unsigned>& v)
96 {
97  v.resize (n+1);
98  v[0]=1;
99 
100  for ( unsigned i = 1; i <= n; ++i)
101  {
102  v[i]= 1;
103  for ( unsigned j= i-1; j>0; --j)
104  v[j] += v[j-1];
105  }
106 }
107 
108 // Used by binomial<n,r>()
109 template<int n, int r> class binomialT
110 {public:enum { value= binomialT<n-1,r-1>::value+binomialT<n-1,r>::value};};
111 template<int n> class binomialT<n,n> {public:enum { value= 1};};
112 template<> class binomialT<0,0> {public:enum { value= 1};};
113 template<int n> class binomialT<n,0> {public:enum { value= 1};};
124 template <unsigned n, unsigned r>
125 inline unsigned binomial () {return binomialT<n,r>::value;}
126 
128 template<class Vec>
129 inline Vec stridesOf(const Vec & sz)
130 {
131  Vec result(sz.size());
132  result[0] = 1;
133  for ( index_t i=1; i != sz.size(); ++i )
134  result[i] = result[i-1] * sz[i-1];
135  return result;
136 }
137 
140 template<class Vec>
141 void firstCombination(const unsigned n, const unsigned r, Vec & res)
142 {
143  if (r<=n)
144  res= Vec::LinSpaced(r,0,r-1);
145  else
146  std::cerr << "Error: r>n combination requested. r="<< r<<", n="<< n<<"\n";
147 }
148 
152 template<class Vec>
153 bool nextCombination (Vec & v, const unsigned n)
154 {
155  const index_t r = v.rows() ;
156  if (v == Vec::LinSpaced(r,n-r,n-1)) return false;
157  int i = r-1;
158  while (v[i] == n-r+i) --i;
159  v[i] += 1;
160  for (index_t j=i+1; j<r; ++j)
161  v[j] = v[i] +j-i;
162  return true;
163 }
164 
170 template<class Vec>
171 void firstPermutation (Vec &current)
172 {
173  const index_t n=current.size();
174  current=Vec::LinSpaced(n,0,n-1);
175 }
176 
182 template<class Vec>
183 bool nextPermutation (Vec &current)
184 {
185  const index_t n=current.size();
186  return std::next_permutation(current.data(), current.data()+n);
187 }
188 
189 
195 template<class Vec>
196 bool nextLexicographic(Vec& cur, const Vec& size)
197 {
198  const index_t d = cur.size();
199  GISMO_ASSERT( d == size.size(), "Vector sizes don't match in nextLexicographic" );
200 
201  for (index_t i = 0; i < d; ++i)
202  {
203  // increase current dimension
204  if (++cur[i] == size[i]) // current dimension exhausted ?
205  {
206  if (i == d - 1) // was it the last one?
207  return false; // then all elements exhausted
208  else
209  cur[i] = 0; // otherwise, reset this to 0 and increase the next dimension
210  }
211  else
212  return true; // current dimension not yet exhausted, return current vector
213  }
214  GISMO_ERROR("Something went wrong in nextLexicographic, wrong input?");
215 }
216 
217 
223 template<class Vec>
224 bool nextLexicographic(Vec& cur, const Vec& start, const Vec& end)
225 {
226  const index_t d = cur.size();
227  GISMO_ASSERT( d == start.size() && d == end.size(),
228  "Vector sizes don't match in nextLexicographic");
229 
230  for (index_t i = 0; i < d; ++i)
231  {
232  // increase current dimension
233  if (++cur[i] == end[i]) // current dimension exhausted ?
234  {
235  if (i == d - 1) // was it the last one?
236  return false; // then all elements exhausted
237  else
238  cur[i] = start[i]; // otherwise, reset this and increase the next dimension
239  }
240  else
241  return true; // current dimension not yet exhausted, return current vector
242  }
243  GISMO_ERROR("Something went wrong in nextLexicographic, wrong input?");
244 }
245 
246 
251 template<class Vec>
252 bool nextCubeVertex(Vec& cur, const Vec& start, const Vec& end)
253 {
254  const int d = cur.size();
255  GISMO_ASSERT( d == start.size() && d == end.size(),
256  "Vector sizes don't match in nextCubeVertex");
257 
258  for (int i = 0; i != d; ++i)
259  {
260  if ( cur[i] != end[i] )
261  {
262  cur[i] = end[i];
263  return true;
264  }
265  else
266  cur[i] = start[i];
267  }
268  return false;
269 }
270 
275 template<class Vec>
276 bool nextCubeVertex(Vec& cur, const Vec& end)
277 {
278  const index_t d = cur.size();
279  GISMO_ASSERT( d == end.size(),
280  "Vector sizes don't match in nextCubeVertex");
281 
282  for (index_t i = 0; i != d; ++i)
283  {
284  if ( cur[i] != end[i] )
285  {
286  cur[i] = end[i];
287  return true;
288  }
289  else
290  cur[i] = 0;
291  }
292  return false;
293 }
294 
301 template<class Vec>
302 bool nextCubeVertex(Vec& cur)
303 {
304  const index_t d = cur.size();
305  GISMO_ASSERT( (cur.array() >= 0).all() && (cur.array() <= 1).all(),
306  "Input must be a vector of zeros and ones, got: "<<cur.transpose() );
307 
308  for (index_t i = 0; i != d; ++i)
309  {
310  if ( cur[i] == 0 )
311  {
312  ++cur[i];
313  return true;
314  }
315  else
316  cur[i] = 0;
317  }
318  return false;
319 }
320 
326 template<class Vec>
327 bool nextCubePoint(Vec& cur, const Vec& end)
328 {
329  const index_t d = cur.size();
330  GISMO_ASSERT(d == static_cast<int>(end.size()),
331  "Vector sizes don't match in nextCubePoint");
332 
333  for (index_t i = 0; i != d; ++i)
334  {
335  if ( cur[i] != end[i] )
336  {
337  ++cur[i];
338  return true;
339  }
340  else
341  cur[i] = 0;
342  }
343  --cur[0];//stopping flag
344  return false;
345 }
346 
352 template<class Vec>
353 bool nextCubePoint(Vec& cur, const Vec& start, const Vec& end)
354 {
355  const index_t d = cur.size();
356  GISMO_ASSERT( d == static_cast<int>(start.size()) &&
357  d == static_cast<int>(end.size()),
358  "Vector sizes don't match in nextCubePoint");
359 
360  for (index_t i = 0; i != d; ++i)
361  {
362  if ( cur[i] != end[i] )
363  {
364  ++cur[i];
365  return true;
366  }
367  else
368  cur[i] = start[i];
369 
370  }
371  --cur[0];//stopping flag
372  return false;
373 }
374 
375 template<class Vec>
376 bool nextCubePoint(Vec & ci, const Vec& start, const Vec& end, const Vec& str)
377 {
378  const index_t d = end.size();
379  GISMO_ASSERT( d == static_cast<int>(start.size()) &&
380  d == static_cast<int>(end.size()),
381  "Vector sizes don't match in nextCubePoint");
382 
383  for (index_t i = 0; i != d; ++i)
384  {
385  if ( ci % str[i] != end[i] ) // cur[i] != end[i]
386  {
387  ci += str[i]; //++cur[i]
388  return true;
389  }
390  else
391  ci -= (end[i]-start[i])*str[i]; // cur[i] = start[i]
392  }
393  ci = end.dot(str)+1;//stopping flag
394  return false;
395 }
396 
401 template<class Vec>
402 bool nextCubeBoundary(Vec& cur, const Vec& start, const Vec& end)
403 {
404  const index_t d = cur.size();
405  GISMO_ASSERT( d == start.size() && d == end.size(),
406  "Vector sizes don't match in nextCubeBoundary");
407 
408  for (index_t i = 0; i != d; ++i)
409  {
410  if ( cur[i] != end[i] )
411  {
412  if ( cur[i] == start[i] && ( i!=d-1 || d==1) ) // || d==1 to treat 1D
413  {
414  int c=i+1;
415  for (int j = c; j!=d; ++j)
416  if ( (cur[j] == start[j]) ||
417  (cur[j] == end[j]) )
418  c++;
419 
420  if ( c==1 )
421  cur[i] = end[i];
422  else
423  cur[i]++;
424  }
425  else
426  cur[i]++;
427 
428  for (int k = i-1; k!=-1; --k)
429  cur[k] = start[k];
430  return true;
431  }
432  }
433  return false;
434 }
435 
441 template<class Vec>
442 bool nextCubeBoundaryOffset(Vec& cur, const Vec& start, const Vec& end, Vec & offset)
443 {
444  const index_t d = cur.size();
445  GISMO_ASSERT( d == start.size() && d == end.size(),
446  "Vector sizes don't match in nextCubeBoundaryOffset");
447 
448  for (index_t i = 0; i != d; ++i)
449  {
450  if ( cur[i] != end[i] )
451  {
452  if ( cur[i] == start[i]+offset[i] && ( i!=d-1 || d==1) ) // || d==1 to treat 1D
453  {
454  int c = i+1;
455  for (int j = c; j!=d; ++j)
456  if (cur[j] <= start[j] + offset[j] ||
457  cur[j] >= end[j] - offset[j] )
458  c++;
459 
460  if ( c==1 )
461  cur[i] = end[i] - offset[i];
462  else
463  cur[i]++;
464  }
465  else
466  cur[i]++;
467 
468  for (int k = i-1; k!=-1; --k)
469  cur[k] = start[k];
470  return true;
471  }
472  }
473 
474  return false;
475 }
476 
482 template<class Vec>
483 bool nextCubeBoundaryOffset(Vec& cur, const Vec& start, const Vec& end,
484  Vec & loffset, Vec & uoffset)
485 {
486  const index_t d = cur.size();
487  GISMO_ASSERT( d == start.size() && d == end.size(),
488  "Vector sizes don't match in nextCubeBoundaryOffset");
489 
490  for (index_t i = 0; i != d; ++i)
491  {
492  if ( cur[i] != end[i] )
493  {
494  if ( cur[i] == start[i]+loffset[i] && ( i!=d-1 || d==1) ) // || d==1 to treat 1D
495  {
496  int c = i+1;
497  for (int j = c; j!=d; ++j)
498  if (cur[j] <= start[j] + loffset[j] ||
499  cur[j] >= end[j] - uoffset[j] )
500  c++;
501 
502  if ( c==1 )
503  cur[i] = end[i] - uoffset[i];
504  else
505  cur[i]++;
506  }
507  else
508  cur[i]++;
509 
510  for (int k = i-1; k!=-1; --k)
511  cur[k] = start[k];
512  return true;
513  }
514  }
515 
516  return false;
517 }
518 
522 inline index_t numCubeElements(const index_t k, const index_t d)
523 {
524  GISMO_ASSERT(k >= 0 && k<=d, "Invalid arguments.");
525  return binomial(d,k) * (1<<(d-k));
526 }
527 
533 template<class Vec>
534 inline index_t dimCubeElement(const Vec & cur)
535 {
536  return (cur.array() == 2).count();
537 }
538 
543 template<class Vec>
544 void firstCubeElement(Vec & cur, const index_t k = 0)
545 {
546  const index_t d = cur.size();
547  GISMO_ASSERT(k >= 0 && k<=d, "Invalid arguments.");
548  cur.topRows (k ).setConstant(2);
549  cur.bottomRows(d-k).setConstant(0);
550 }
551 
558 template<class Vec>
559 bool nextCubeElement(Vec & cur, const index_t k)
560 {
561  const index_t d = cur.size();
562  GISMO_ASSERT(k >= 0 && k<=cur.size(), "Invalid arguments.");
563 
564  index_t i;
565  do
566  {
567  for (i = 0; i != d; ++i)
568  {
569  if ( cur[i] != 2 )
570  {
571  ++cur[i];
572  if ( (cur.array() == 2).count() == k ) // dimCubeElement(cur)==k ?
573  return true;
574  else
575  break;// skip face
576  }
577  else
578  cur[i] = 0;
579  }
580  }
581  while ( i!=d );
582 
583  return false;
584 }
585 
596 template <typename Z, int d>
597 void cubeIsometry( const gsVector<bool,d> & flip,
598  const gsVector<index_t,d> & perm,
599  gsVector<Z> & result)
600 {
601  const index_t dd = flip.size(); //binary sequence of length d
602  GISMO_ASSERT( dd == perm.size(), "Dimensions do not match in cubeIsometry");
603  GISMO_ASSERT( perm.sum() == dd*(dd-1)/2, "Error in the permutation: "<< perm.transpose());
604 
605  gsVector<index_t,d> pstr(dd);
606  for (index_t k=0; k!=dd; ++k)
607  pstr[k] = (1<<perm[k]);
608 
609  result.resize(1<<dd);
610  index_t r = 0;
611  index_t i;
613  do
614  {
615  Z & c = result[r++];
616  c = 0;
617  for (index_t k=0; k!=dd; ++k)
618  c += ( flip[perm[k]] == v[k] ) * pstr[k];
619 
620  for (i = 0; i != dd; ++i)
621  {
622  if ( !v[i] )
623  {
624  v[i] = true;
625  break;//for
626  }
627  else
628  v[i] = false;
629  }
630  }
631  while (i!=dd);
632 }
633 
644 template <int d>
646  const gsVector<index_t,d> & perm,
647  gsMatrix<int,d,d> & result)
648 {
649  result.setZero(d,d);
650  for(index_t i = 0; i < d; ++i)
651  result(perm(i),i) = (flip(perm(i)) ? 1 : -1);
652 }
653 
656 template<class Vec>
657 void firstComposition( typename Vec::Scalar sum, index_t dim, Vec & res)
658 {
659  res.derived().resize(dim);
660  res.setZero();
661  res[0] = sum;
662 }
663 
666 template<class Vec>
667 inline bool nextComposition(Vec & v)
668 {
669  const index_t k = v.size() - 1;
670 
671  if (v[k] != v.sum())
672  {
673  for (index_t i = 0; i <= k; ++i)
674  {
675  if ( v[i]!=0 )
676  {
677  const typename Vec::Scalar t = v[i];
678  v[i] = 0 ;
679  v[0] = t-1;
680  v[i+1] += 1 ;
681  return true;
682  }
683  }
684  }
685  return false;
686 }
687 
688 
691 inline unsigned numCompositions(int sum, short_t dim)
692 {
693  return binomial(sum+dim-1,dim-1);
694 }
695 
696 
700 template<class Vec, class Mat>
701 void firstMultiComposition(const Vec & a, index_t k, Mat & res)
702 {
703  const index_t d = a.size();
704  res.setZero(k, d);
705  res.row(0) = a.transpose();
706 }
707 
716 template<class Mat>
717 inline bool nextMultiComposition(Mat & m)
718 {
719  const index_t k = m.rows();
720  const index_t d = m.cols();
721 
722  for (index_t j = 0; j != d; ++j)
723  {
724  typename Mat::ColXpr c_j = m.col(j);
725  if ( nextComposition(c_j) )
726  return true;
727  else
728  {
729  const index_t n_j = c_j.sum();
730  firstComposition(n_j, k, c_j);
731  }
732  }
733  return false;
734 }
735 
736 
740 template<class Vec>
741 unsigned numMultiCompositions(const Vec & a, index_t k)
742 {
743  unsigned result = 1;
744  const index_t d = a.size();
745  for (index_t j = 0; j != d; ++j)
746  result *= binomial<unsigned>(a[j]+k-1, k-1);
747  return result;
748 }
749 
750 
751 // Lexicographic comparison for gsVectors
752 template<class Z, unsigned d>
753 struct lex_less
754 {
755  bool operator() (const gsVector<Z,d> & lhs, const gsVector<Z,d> & rhs) const
756  {
757  unsigned i = 0;
758  while( (i<d) && (lhs[i] == rhs[i++]) ) ;
759  return ( --i==d ? false : lhs[i] < rhs[i] );
760  }
761 };
762 
763 
764 } // namespace gismo
Z binomial(const Z n, const Z r)
Computes the binomial expansion coefficient binomial(n,r)
Definition: gsCombinatorics.h:69
bool nextCubePoint(Vec &cur, const Vec &end)
Iterate in lexigographic order through the points of the integer lattice contained in the cube [0...
Definition: gsCombinatorics.h:327
bool nextCubeBoundary(Vec &cur, const Vec &start, const Vec &end)
Iterates in lex-order through the boundary points of the cube [start,end]. Updates cur with the curre...
Definition: gsCombinatorics.h:402
void firstComposition(typename Vec::Scalar sum, index_t dim, Vec &res)
Construct first composition of sum into dim integers.
Definition: gsCombinatorics.h:657
#define short_t
Definition: gsConfig.h:35
bool nextMultiComposition(Mat &m)
Returns (inplace) the next multi-composition in lexicographic order.
Definition: gsCombinatorics.h:717
#define index_t
Definition: gsConfig.h:32
void firstMultiComposition(const Vec &a, index_t k, Mat &res)
Constructs first multi-composition of a = (a_1,..,a_d) into k integers.
Definition: gsCombinatorics.h:701
index_t numCubeElements(const index_t k, const index_t d)
Returns the number of elements (faces) of dimension k of a d-cube.
Definition: gsCombinatorics.h:522
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition: gsMatrix.h:38
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
index_t dimCubeElement(const Vec &cur)
Returns the dimension of an element (face) of the d-cube [0,1]^d. The element is expected to contain ...
Definition: gsCombinatorics.h:534
bool nextComposition(Vec &v)
Returns (inplace) the next composition in lexicographic order.
Definition: gsCombinatorics.h:667
void firstPermutation(Vec &current)
changes current to the first permutation of 0 ... size(current)-1 note that you must resize the vecto...
Definition: gsCombinatorics.h:171
Mathematical functions for use in G+Smo.
void firstCubeElement(Vec &cur, const index_t k=0)
Updates cur to contain the lexicographically first element (face) of the cube [0,1]^d of dimension k...
Definition: gsCombinatorics.h:544
void firstCombination(const unsigned n, const unsigned r, Vec &res)
Computes the first r-combination of {0,..,n-1}.
Definition: gsCombinatorics.h:141
bool nextPermutation(Vec &current)
Changes current to the next lexicographically ordered permutation.
Definition: gsCombinatorics.h:183
unsigned numMultiCompositions(const Vec &a, index_t k)
Number of multi-composition of a = (a_1,..,a_d) into k integers.
Definition: gsCombinatorics.h:741
bool nextCubeBoundaryOffset(Vec &cur, const Vec &start, const Vec &end, Vec &offset)
Iterates in lex-order through the boundary points of the cube [start,end], with an \ offset to the in...
Definition: gsCombinatorics.h:442
bool nextCombination(Vec &v, const unsigned n)
Computes the next r-combination of {0,..,n-1}, where r = v.size(). The input v is expected to be a va...
Definition: gsCombinatorics.h:153
bool nextLexicographic(Vec &cur, const Vec &size)
Iterates through a tensor lattice with the given size. Updates cur and returns true if another entry ...
Definition: gsCombinatorics.h:196
Vec stridesOf(const Vec &sz)
Computes the of a vector.
Definition: gsCombinatorics.h:129
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
bool nextCubeElement(Vec &cur, const index_t k)
Iterates in lexicographic order through the elements (faces) of dimension k of the cube [0...
Definition: gsCombinatorics.h:559
This is the main header file that collects wrappers of Eigen for linear algebra.
void cubeIsometryMatrix(const gsVector< bool, d > &flip, const gsVector< index_t, d > &perm, gsMatrix< int, d, d > &result)
Computes the rotation matrix implied by a permutation perm of the cube directions plus a relocation f...
Definition: gsCombinatorics.h:645
void cubeIsometry(const gsVector< bool, d > &flip, const gsVector< index_t, d > &perm, gsVector< Z > &result)
Computes the isometry of the unit d-cube implied by a permutation perm of the cube directions plus a ...
Definition: gsCombinatorics.h:597
unsigned numCompositions(int sum, short_t dim)
Number of compositions of sum into dim integers.
Definition: gsCombinatorics.h:691
unsigned factorial(unsigned n)
Returns the factorial of n i.e. n! Remember that factorial grow too fast and only n! with n&lt;=13 can b...
Definition: gsCombinatorics.h:29
void binomial_into(unsigned n, gsVector< unsigned > &v)
Returns a vector containing all the binomials (n,r) with n fixed.
Definition: gsCombinatorics.h:95
bool nextCubeVertex(Vec &cur, const Vec &start, const Vec &end)
Iterate in lexicographic order through the vertices of the cube [start,end]. Updates cur with the cur...
Definition: gsCombinatorics.h:252