KASKADE 7 development version
combinatorics.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2019 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef COMBINATORICS_HH
14#define COMBINATORICS_HH
15
16#include <algorithm>
17#include <numeric>
18#include <cassert>
19#include <functional>
20
21namespace Kaskade
22{
29 constexpr int binomial(int n, int k)
30 {
31 assert(0<=k && k<=n);
32
33 if (2*k>n)
34 k = n-k;
35
36 if (k==0)
37 return 1;
38
39 // Use the product form for efficiency and overflow avoidance.
40 int r = n;
41 for (int i=2; i<=k; ++i)
42 {
43 r *= n+1-i;
44 r /= i;
45 }
46
47 return r;
48 }
49
50 // ----------------------------------------------------------------------------------------------
51
60 template <size_t m>
61 size_t multinomial(std::array<size_t,m> const& ks)
62 {
63 size_t r = 1;
64 size_t n = std::accumulate(begin(ks),end(ks),0);
65
66 // Compute the multinomial factor as the binomial one above.
67 for (size_t k: ks)
68 for (size_t i=1; i<=k; ++i)
69 {
70 r *= n;
71 r /= i;
72 --n;
73 }
74
75 return r;
76 }
77
78 // ----------------------------------------------------------------------------------------------
79
89 constexpr int numberOfMultiindices(int d, int m)
90 {
91 int n = 0;
92
93 if (d==1)
94 return m+1;
95
96 if (d==2)
97 return (m+2)*(m+1)/2;
98
99 for (int i=0; i<=m; ++i)
100 n += numberOfMultiindices(d-1,i);
101 return n;
102 }
103
104 // ----------------------------------------------------------------------------------------------
105
117 template <int d>
118 std::array<size_t,d> multiIndex(size_t m, size_t n)
119 {
120 static_assert(d>=1,"multiindices only defined for d>0");
121 assert(n < numberOfMultiindices(d,m));
122
123 std::array<size_t,d> ks;
124
125 if constexpr (d==1)
126 {
127 ks[0] = n;
128 }
129 else
130 {
131 size_t i = 0;
132 size_t l = 0;
133 while (n >= l+numberOfMultiindices(d-1,m-i))
134 {
135 l += numberOfMultiindices(d-1,m-i);
136 ++i;
137 }
138 assert(n >= l);
139 ks[d-1] = i;
140 auto hs = multiIndex<d-1>(m-i,n-l);
141 std::copy(begin(hs),end(hs),begin(ks));
142 }
143
144 return ks;
145 }
146
147 // ----------------------------------------------------------------------------------------------
148
156 template <class It>
157 void next_multiindex(It first, It last, int const m)
158 {
159 // If the sum limit is reached, we need to "make room" for an increment.
160 if (std::accumulate(first,last,0)==m)
161 {
162 // Find the first (i.e. least significant) nonzero entry and set it to zero.
163 first = std::find_if(first,last,std::bind2nd(std::not_equal_to<int>(),0));
164 assert(first!=last);
165 *first = 0;
166 // Move to the next higher (i.e. more significant) entry.
167 ++first;
168 }
169
170 // Increment the relevant index.
171 if (first!=last)
172 ++(*first);
173 }
174} /* end of namespace Kaskade */
175
176
177#endif
std::array< size_t, d > multiIndex(size_t m, size_t n)
Random access to multiindices.
size_t multinomial(std::array< size_t, m > const &ks)
Computes the multinomial coefficient , where .
constexpr int binomial(int n, int k)
Computes the binomial coefficient .
void next_multiindex(It first, It last, int const m)
Computes the next nonnegative multiindex of order m.
constexpr int numberOfMultiindices(int d, int m)
Computes the number of multiindices of order m and dimension d.