KASKADE 7 development version
Loading...
Searching...
No Matches
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
92 constexpr int numberOfMultiindices(int d, int m)
93 {
94 int n = 0;
95
96 if (d==1)
97 return m+1;
98
99 if (d==2)
100 return (m+2)*(m+1)/2;
101
102 for (int i=0; i<=m; ++i)
103 n += numberOfMultiindices(d-1,i);
104
105 return n;
106 }
107
108 // ----------------------------------------------------------------------------------------------
109
124 template <int d>
125 std::array<size_t,d> multiIndex(size_t m, size_t n)
126 {
127 static_assert(d>=1,"multiindices only defined for d>0");
128 assert(n < numberOfMultiindices(d,m));
129
130 std::array<size_t,d> ks;
131
132 if constexpr (d==1)
133 {
134 ks[0] = n;
135 }
136 else
137 {
138 size_t i = 0;
139 size_t l = 0;
140 while (n >= l+numberOfMultiindices(d-1,m-i))
141 {
142 l += numberOfMultiindices(d-1,m-i);
143 ++i;
144 }
145 assert(n >= l);
146 ks[d-1] = i;
147 auto hs = multiIndex<d-1>(m-i,n-l);
148 std::copy(begin(hs),end(hs),begin(ks));
149 }
150
151 return ks;
152 }
153
154 // ----------------------------------------------------------------------------------------------
155
166 template <class It>
167 void next_multiindex(It first, It last, int const m)
168 {
169 // If the sum limit is reached, we need to "make room" for an increment.
170 if (std::accumulate(first,last,0)==m)
171 {
172 // Find the first (i.e. least significant) nonzero entry and set it to zero.
173 first = std::find_if(first,last,[](int k) { return k!=0; });
174 assert(first!=last);
175 *first = 0;
176 // Move to the next higher (i.e. more significant) entry.
177 ++first;
178 }
179
180 // Increment the relevant index.
181 if (first!=last)
182 ++(*first);
183 }
184} /* end of namespace Kaskade */
185
186
187#endif
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 .