HyperHDG
combinations.h
Go to the documentation of this file.
1 #ifndef TPCC_COMBINATIONS_H
2 #define TPCC_COMBINATIONS_H
3 
4 #include <array>
5 #include <cassert>
6 #include <ostream>
7 
8 namespace TPCC
9 {
16 template <typename T = unsigned int>
17 constexpr T binomial(T n, T k)
18 {
19  if (n < k)
20  return 0;
21  T result = 1;
22  if (k > n / 2)
23  k = n - k;
24  for (T i = 1; i <= k; ++i)
25  {
26  result *= n + 1 - i;
27  result /= i;
28  }
29 
30  return result;
31 }
32 
39 template <typename T = unsigned int, T n, T k>
40 constexpr std::array<T, n - k> compute_complement(std::array<T, k> combi)
41 {
42  std::array<unsigned int, n - k> result{};
43  unsigned int vpos = 0;
44  unsigned int current = n - 1;
45 
46  for (unsigned int i = 0; i < n - k; ++i, --current)
47  {
48  while (vpos < k && current == combi[vpos])
49  {
50  --current;
51  ++vpos;
52  }
53  result[i] = current;
54  }
55  return result;
56 }
57 
61 template <int n, int k, typename T = unsigned int>
63 {
65  std::array<T, k> data;
67  std::array<T, n - k> cdata;
68 
69 public:
70  Combination(const std::array<T, k>& combi, const std::array<T, n - k>& comp)
71  : data(combi)
72  , cdata(comp)
73  {
74  }
79  T in(unsigned int i) const { return data[i]; }
84  T out(unsigned int i) const { return cdata[i]; }
85 
89  Combination<n, n - k, T> complement() const { return Combination<n, n - k, T>(cdata, data); }
90 
97  template <int kk = k>
98  constexpr typename std::enable_if<(kk > 0), Combination<n, k - 1, T>>::type eliminate(
99  unsigned int i) const
100  {
101  std::array<T, k - 1> outdata{};
102  for (unsigned int j = 0; j < i; ++j)
103  outdata[j] = data[j];
104  const T tmp = data[i];
105  for (unsigned int j = i; j < k - 1; ++j)
106  outdata[j] = data[j + 1];
107 
108  std::array<T, n - k + 1> outcdata{};
109  unsigned int jj = 0, j = 0;
110  for (; j < n - k; ++j, ++jj)
111  {
112  if (jj == j && cdata[j] < tmp)
113  {
114  outcdata[j] = tmp;
115  ++jj;
116  }
117  outcdata[jj] = cdata[j];
118  }
119  if (jj == j)
120  outcdata[n - k] = tmp;
121  return Combination<n, k - 1>{ outdata, outcdata };
122  }
129  template <int kk = k>
130  constexpr typename std::enable_if<(kk < n), Combination<n, k + 1, T>>::type add(
131  unsigned int i) const
132  {
133  std::array<T, k + 1> outdata{};
134  int jj = 0, j = 0;
135  for (; j < k; ++j, ++jj)
136  {
137  if (jj == j && data[j] <= i)
138  {
139  assert(data[j] != i);
140  outdata[j] = i;
141  ++jj;
142  }
143  outdata[jj] = data[j];
144  }
145  if (jj == j)
146  outdata[k] = i;
147 
148  std::array<T, n - k - 1> outcdata{};
149  j = 0;
150  jj = 0;
151  for (; j < n - k - 1; ++j, ++jj)
152  {
153  if (cdata[j] == i)
154  ++jj;
155  outcdata[j] = cdata[jj];
156  }
157  return Combination<n, k + 1>{ outdata, outcdata };
158  }
159 
163  template <int kk = k>
164  constexpr typename std::enable_if<(kk <= n), Combination<n + 1, k + 1, T>>::type add_and_expand(
165  unsigned int i) const
166  {
167  std::array<T, n + 1 - k> outcdata{};
168  std::copy(cdata.begin(), cdata.end(), outcdata.begin());
169  outcdata[n - k] = n;
170  return Combination<n + 1, k>{ data, outcdata }.add(i);
171  }
172 
176  void print_debug(std::ostream& os) const
177  {
178  for (int i = 0; i < k; ++i)
179  os << in(i);
180  os << ':';
181  for (int i = 0; i < n - k; ++i)
182  os << out(i);
183  }
184 };
185 
194 template <int n, int k>
196 {
200  static constexpr unsigned int size();
201 
205  constexpr Combination<n, k> operator[](unsigned int);
206 
211  static std::array<unsigned int, k> value(unsigned int index);
220  static std::array<unsigned int, n - k> dual(unsigned int index);
221 
225  template <typename T>
226  static constexpr unsigned int index(const Combination<n, k, T>& combi);
227 
228 private:
233  template <unsigned int size, typename... I>
234  static constexpr std::array<unsigned int, k> compute_value(unsigned int index, I... args);
235 };
236 
237 //----------------------------------------------------------------------//
238 
239 template <int n, int k>
240 constexpr unsigned int Combinations<n, k>::size()
241 {
242  return binomial(n, k);
243 }
244 
245 template <int n, int k>
246 template <unsigned int sz, typename... I>
247 constexpr std::array<unsigned int, k> Combinations<n, k>::compute_value(unsigned int index,
248  I... args)
249 {
250  if (index > size())
251  abort();
252  if constexpr (sz == 1)
253  return std::array<unsigned int, k>{ args..., index };
254  else
255  {
256  unsigned int cs = sz - 1;
257  unsigned int bn = 0;
258  for (; cs <= n; ++cs)
259  {
260  unsigned int bi = binomial(cs, sz);
261  if (bi > index)
262  break;
263  bn = bi;
264  }
265  --cs;
266  return compute_value<sz - 1>(index - bn, args..., cs);
267  }
268 }
269 
270 template <int n, int k>
271 template <typename T>
272 inline constexpr unsigned int Combinations<n, k>::index(const Combination<n, k, T>& combi)
273 {
274  unsigned int result = 0;
275  if constexpr (k > 0)
276  for (unsigned int i = 0; i < k; ++i)
277  result += binomial(combi.in(i), k - i);
278  return result;
279 }
280 
281 //----------------------------------------------------------------------//
282 
283 template <int n, int k>
284 std::array<unsigned int, k> Combinations<n, k>::value(unsigned int index)
285 {
286  if constexpr (k == 0)
287  {
288  ++index; // Avoid warning about unused variable
289  return std::array<unsigned int, 0>();
290  }
291  else
292  return compute_value<k>(index);
293 }
294 
295 template <int n, int k>
296 std::array<unsigned int, n - k> Combinations<n, k>::dual(unsigned int index)
297 {
298  if constexpr (k == 0)
300  auto v = value(index);
301  return compute_complement<unsigned int, n, k>(v);
302 }
303 
304 template <int n, int k>
306 {
307  return Combination<n, k>(value(index), dual(index));
308 }
309 } // namespace TPCC
310 
311 #endif
TPCC::compute_complement
constexpr std::array< T, n - k > compute_complement(std::array< T, k > combi)
Definition: combinations.h:40
TPCC::Combination::eliminate
constexpr std::enable_if<(kk > 0), Combination< n, k - 1, T > >::type eliminate(unsigned int i) const
The combination obtained by eliminating the ith element.
Definition: combinations.h:98
TPCC::Combination::data
std::array< T, k > data
The array of members.
Definition: combinations.h:65
check_push_test.index
index
Definition: check_push_test.py:10
TPCC::Combination::print_debug
void print_debug(std::ostream &os) const
Print the content of this object for debugging.
Definition: combinations.h:176
copy
and that you are informed that you can do these things To protect your we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it For if you distribute copies of the whether gratis or for a you must give the recipients all the rights that we gave you You must make sure that receive or can get the source code If you link other code with the you must provide complete object files to the so that they can relink them with the library after making changes to the library and recompiling it And you must show them these terms so they know their rights We protect your rights with a two step which gives you legal permission to copy
Definition: License.txt:50
TPCC::Combinations::index
static constexpr unsigned int index(const Combination< n, k, T > &combi)
The index of a combination within the lexicographic enumeration.
Definition: combinations.h:272
TPCC::Combination::Combination
Combination(const std::array< T, k > &combi, const std::array< T, n - k > &comp)
Definition: combinations.h:70
TPCC::Combination::cdata
std::array< T, n - k > cdata
The array of non-members.
Definition: combinations.h:67
TPCC::Combination::add
constexpr std::enable_if<(kk< n), Combination< n, k+1, T > >::type add(unsigned int i) const
The combination obtained by adding the element i.
Definition: combinations.h:130
TPCC
Definition: combinations.h:8
TPCC::Combination::complement
Combination< n, n - k, T > complement() const
Return the complement of this combination.
Definition: combinations.h:89
TPCC::Combination::add_and_expand
constexpr std::enable_if<(kk<=n), Combination< n+1, k+1, T > >::type add_and_expand(unsigned int i) const
The combination out of n+1 obtained by adding one element.
Definition: combinations.h:164
TPCC::Combinations::dual
static std::array< unsigned int, n - k > dual(unsigned int index)
The array of numbers (of length n-k) of numbers not in the combination of the given index.
Definition: combinations.h:296
TPCC::Combinations::size
static constexpr unsigned int size()
The number of such combinations.
Definition: combinations.h:240
TPCC::Combination::in
T in(unsigned int i) const
The ith element which is part of the combination in descending order.
Definition: combinations.h:79
TPCC::Combination
Dataset for a combination k out of n.
Definition: combinations.h:62
TPCC::Combination::out
T out(unsigned int i) const
The ith element which is not part of the combination in descending order.
Definition: combinations.h:84
TPCC::Combinations::value
static std::array< unsigned int, k > value(unsigned int index)
The array of numbers (of length k) in the combination with given index.
Definition: combinations.h:284
TPCC::Combinations::compute_value
static constexpr std::array< unsigned int, k > compute_value(unsigned int index, I... args)
The function template computing the combination in lexicographic ordering recursively.
Definition: combinations.h:247
TPCC::Combinations
Definition: combinations.h:195
TPCC::binomial
constexpr T binomial(T n, T k)
Compute the binomial coefficient n over k.
Definition: combinations.h:17
TPCC::Combinations::operator[]
constexpr Combination< n, k > operator[](unsigned int)
A boolean array of length n with a true for each selected value.
Definition: combinations.h:305