G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsCombinatorics.h
Go to the documentation of this file.
1
14#pragma once
15
17#include <gsCore/gsMath.h>
18
19namespace gismo
20{
21
27// \ingroup Utils
28// could also be in Utils, but doxygen allows only one group for free functions
29inline 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
41inline unsigned long long factorial( unsigned long long n)
42{
43static 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 };
44GISMO_ASSERT(n < util::size(precomputed), "Overflow when computing factorial.");
45return precomputed[n];
46}
47*/
48
66// \ingroup Utils
67// Note: could also be in Utils, but doxygen allows only one group for free functions
68template <typename Z>
69inline 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
95inline 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>()
109template<int n, int r> class binomialT
110{public:enum { value= binomialT<n-1,r-1>::value+binomialT<n-1,r>::value};};
111template<int n> class binomialT<n,n> {public:enum { value= 1};};
112template<> class binomialT<0,0> {public:enum { value= 1};};
113template<int n> class binomialT<n,0> {public:enum { value= 1};};
124template <unsigned n, unsigned r>
125inline unsigned binomial () {return binomialT<n,r>::value;}
126
128template<class Vec>
129inline 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
140template<class Vec>
141void 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
152template<class Vec>
153bool 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
170template<class Vec>
171void firstPermutation (Vec &current)
172{
173 const index_t n=current.size();
174 current=Vec::LinSpaced(n,0,n-1);
175}
176
182template<class Vec>
183bool nextPermutation (Vec &current)
184{
185 const index_t n=current.size();
186 return std::next_permutation(current.data(), current.data()+n);
187}
188
189
195template<class Vec>
196bool 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
223template<class Vec>
224bool 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
251template<class Vec>
252bool 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
275template<class Vec>
276bool 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
301template<class Vec>
302bool 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
326template<class Vec>
327bool 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
352template<class Vec>
353bool 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
375template<class Vec>
376bool 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
401template<class Vec>
402bool 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
441template<class Vec>
442bool 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
482template<class Vec>
483bool 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
522inline 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
533template<class Vec>
534inline index_t dimCubeElement(const Vec & cur)
535{
536 return (cur.array() == 2).count();
537}
538
543template<class Vec>
544void 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
558template<class Vec>
559bool 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
596template <typename Z, int d>
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
644template <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
656template<class Vec>
657void 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
666template<class Vec>
667inline 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
691inline unsigned numCompositions(int sum, short_t dim)
692{
693 return binomial(sum+dim-1,dim-1);
694}
695
696
700template<class Vec, class Mat>
701void 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
716template<class Mat>
717inline 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
740template<class Vec>
741unsigned 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
752template<class Z, unsigned d>
753struct 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
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
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
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 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
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
bool nextComposition(Vec &v)
Returns (inplace) the next composition in lexicographic order.
Definition gsCombinatorics.h:667
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 nextPermutation(Vec &current)
Changes current to the next lexicographically ordered permutation.
Definition gsCombinatorics.h:183
bool nextMultiComposition(Mat &m)
Returns (inplace) the next multi-composition in lexicographic order.
Definition gsCombinatorics.h:717
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 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 firstComposition(typename Vec::Scalar sum, index_t dim, Vec &res)
Construct first composition of sum into dim integers.
Definition gsCombinatorics.h:657
unsigned numCompositions(int sum, short_t dim)
Number of compositions of sum into dim integers.
Definition gsCombinatorics.h:691
unsigned binomial()
Returns binomial(n,r) as a compile time constant.
Definition gsCombinatorics.h:125
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
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
void firstCombination(const unsigned n, const unsigned r, Vec &res)
Computes the first r-combination of {0,..,n-1}.
Definition gsCombinatorics.h:141
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
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
unsigned factorial(unsigned n)
Returns the factorial of n i.e. n! Remember that factorial grow too fast and only n!...
Definition gsCombinatorics.h:29
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
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
void binomial_into(unsigned n, gsVector< unsigned > &v)
Returns a vector containing all the binomials (n,r) with n fixed.
Definition gsCombinatorics.h:95
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
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
This is the main header file that collects wrappers of Eigen for linear algebra.
Mathematical functions for use in G+Smo.
The G+Smo namespace, containing all definitions for the library.
Vec stridesOf(const Vec &sz)
Computes the of a vector.
Definition gsCombinatorics.h:129