C++ Library Extensions 2022.12.09
To help learn modern C++ programming
cpg_combinatorics.hpp
Go to the documentation of this file.
1/*
2 Author: Thomas Kim
3 First Edit: July 29, 2021
4*/
5
6#ifndef CPG_COMBINATORICS_HPP
7#define CPG_COMBINATORICS_HPP
8
9#ifndef NOMINMAX
10#define NOMINMAX
11#endif
12
13#include "cpg_rational.hpp"
14#include "cpg_iterator.hpp"
15
16#include <functional>
17
19{
20 namespace hidden
21 {
22 template<typename ElementType>
23 auto product_base(std::vector<ElementType> const& A, std::vector<ElementType> const& B)
24 {
25 std::vector< std::vector<ElementType> > result;
26 result.reserve( A.size() * B.size() );
27
28 for(auto& a: A)
29 {
30 for(auto& b: B)
31 result.emplace_back( std::vector<ElementType>{a, b} );
32 }
33
34 return result;
35 }
36
37 template<typename ElementType>
38 auto product_base( std::vector< std::vector<ElementType> > const& power_set, std::vector<ElementType> const& B)
39 {
40 std::vector<std::vector<ElementType>> result;
41 result.reserve( power_set.size() * B.size() );
42
43 for(auto& P: power_set)
44 {
45 for(auto& b: B)
46 {
47 auto A = P;
48
49 A.emplace_back(b);
50
51 result.emplace_back(A);
52 }
53 }
54
55 return result;
56 }
57
58 template<typename ElementType, typename... VectorTypes>
59 auto product_base(std::vector< std::vector<ElementType> > const& power_set,
60 std::vector<ElementType> const& A, std::vector<ElementType> const& B, VectorTypes&&... tails)
61 {
62 return product_base( product_base(power_set, A), B, tails...);
63 }
64
65 template<typename ElementType, typename... VectorTypes>
66 auto product_base(std::vector<ElementType> const& A, std::vector<ElementType> const& B,
67 std::vector<ElementType> const& C, VectorTypes&&... tails)
68 {
69 return product_base( product_base(A, B), C, tails...) ;
70 }
71
73
74 template<typename SetWiseConstraintType, typename ElementType>
75 requires requires (SetWiseConstraintType constraint)
76 {
77 { constraint( std::vector<ElementType>{} ) } -> std::same_as<bool>;
78 }
79 auto product_base(SetWiseConstraintType&& set_wise_constraint,
80 std::vector<ElementType> const& A, std::vector<ElementType> const& B)
81 {
82 std::vector< std::vector<ElementType> > result;
83 result.reserve( A.size() * B.size() );
84
85 for(auto& a: A)
86 {
87 for(auto& b: B)
88 {
89 auto R = std::vector<ElementType>{a, b};
90
91 if(set_wise_constraint(R))
92 result.emplace_back( std::move(R) );
93 }
94 }
95
96 return result;
97 }
98
99 template<typename SetWiseConstraintType, typename ElementType>
100 requires requires (SetWiseConstraintType constraint)
101 {
102 { constraint( std::vector<ElementType>{} ) } -> std::same_as<bool>;
103 }
104 auto product_base(SetWiseConstraintType&& set_wise_constraint,
105 std::vector< std::vector<ElementType> > const& power_set, std::vector<ElementType> const& B)
106 {
107 std::vector<std::vector<ElementType>> result;
108 result.reserve( power_set.size() * B.size() );
109
110 for(auto& P: power_set)
111 {
112 for(auto& b: B)
113 {
114 auto A = P;
115
116 A.emplace_back(b);
117
118 if(set_wise_constraint(A))
119 result.emplace_back(std::move(A));
120 }
121 }
122
123 return result;
124 }
125
126 template<typename SetWiseConstraintType, typename ElementType, typename... VectorTypes>
127 requires requires (SetWiseConstraintType constraint)
128 {
129 { constraint( std::vector<ElementType>{} ) } -> std::same_as<bool>;
130 }
131 auto product_base(SetWiseConstraintType&& set_wise_constraint, std::vector< std::vector<ElementType> > const& power_set,
132 std::vector<ElementType> const& A, std::vector<ElementType> const& B, VectorTypes&&... tails)
133 {
134 return product_base(set_wise_constraint, product_base(set_wise_constraint, power_set, A), B, tails...);
135 }
136
137 template<typename SetWiseConstraintType, typename ElementType, typename... VectorTypes>
138 requires requires (SetWiseConstraintType constraint)
139 {
140 { constraint( std::vector<ElementType>{} ) } -> std::same_as<bool>;
141 }
142 auto product_base(SetWiseConstraintType&& set_wise_constraint,
143 std::vector<ElementType> const& A, std::vector<ElementType> const& B,
144 std::vector<ElementType> const& C, VectorTypes&&... tails)
145 {
146 return product_base(set_wise_constraint, product_base(set_wise_constraint, A, B), C, tails...) ;
147 }
148 }
149 // end of namespace hidden
150
151 template<typename ElementType, typename... VectorTypes>
152 requires requires
153 {
154 requires ( std::same_as<std::vector<ElementType>, std::remove_cvref_t<VectorTypes>> && ... );
155 }
156 auto product(std::vector<ElementType> const& A, std::vector<ElementType> const& B, VectorTypes... tails)
157 {
158 return hidden::product_base(A, B, tails...);
159 }
160
161 template<typename SetWiseConstraintType, typename ElementType, typename... VectorTypes>
162 requires requires (SetWiseConstraintType constraint)
163 {
164 { constraint( std::vector<ElementType>{} ) } -> std::same_as<bool>;
165 requires ( std::same_as<std::vector<ElementType>, std::remove_cvref_t<VectorTypes>> && ... );
166 }
167 auto product(SetWiseConstraintType&& set_wise_constraint,
168 std::vector<ElementType> const& A, std::vector<ElementType> const& B, VectorTypes... tails)
169 {
170 return hidden::product_base(set_wise_constraint, A, B, tails...);
171 }
172
173 template<typename TransformerType, typename ElementType, typename... VectorTypes>
174 auto product(TransformerType&& transformer,
175 std::vector<ElementType> const& A, std::vector<ElementType> const& B, VectorTypes... tails)
176 requires requires(std::vector<ElementType> v)
177 {
178 { transformer(v) } -> std::same_as<std::vector<ElementType>>;
179 requires ( std::same_as<std::vector<ElementType>, std::remove_cvref_t<VectorTypes>> && ... );
180 }
181 {
182 return hidden::product_base(transformer(A), transformer(B), transformer(tails)...);
183 }
184
186 template<typename TranformerType, typename SetWiseConstraintType, typename ElementType, typename... VectorTypes>
187 requires requires (SetWiseConstraintType constraint)
188 {
189 { constraint( std::vector<ElementType>{} ) } -> std::same_as<bool>;
190 requires ( std::same_as<std::vector<ElementType>, std::remove_cvref_t<VectorTypes>> && ... );
191 }
192 auto product(TranformerType&& transformer, SetWiseConstraintType&& set_wise_constraint,
193 std::vector<ElementType> const& A, std::vector<ElementType> const& B, VectorTypes... tails)
194 requires requires(std::vector<ElementType> v)
195 {
196 { transformer(v) } -> std::same_as<std::vector<ElementType>>;
197 }
198 {
199 return hidden::product_base(set_wise_constraint, transformer(A), transformer(B), transformer(tails)...);
200 }
201
202 template<typename TranformerType, typename SetWiseConstraintType, typename ElementType, typename... VectorTypes>
203 requires requires (SetWiseConstraintType constraint)
204 {
205 { constraint( std::vector<ElementType>{} ) } -> std::same_as<bool>;
206 requires ( std::same_as<std::vector<ElementType>, std::remove_cvref_t<VectorTypes>> && ... );
207 }
208 auto product(SetWiseConstraintType&& set_wise_constraint, TranformerType&& transformer,
209 std::vector<ElementType> const& A, std::vector<ElementType> const& B, VectorTypes... tails)
210 requires requires(std::vector<ElementType> v)
211 {
212 { transformer(v) } -> std::same_as<std::vector<ElementType>>;
213 }
214 {
215 return hidden::product_base(set_wise_constraint, transformer(A), transformer(B), transformer(tails)...);
216 }
217
219 template<typename ElementType, typename AllocatorType, typename T1, typename T2>
220 std::vector<ElementType, AllocatorType> atomized_permutation(
221 std::vector<ElementType, AllocatorType> S, T1 r, T2 m_th, bool RemoveTails = false)
222 {
223 using T = std::common_type_t<T1, T2>;
224
225 T n = (T) S.size();
226 T rr = r;
227
228 if( (T)r < (T)1 || (T)n < (T)1 || (T)r > (T)n)
229 {
230 if(RemoveTails && S.size() != rr)
231 S.erase(S.begin() + rr, S.end());
232
233 return S;
234 }
235
236 auto npr = rational_number::nPr( n-1, r-1);
237
238 if(!npr.has_value())
239 {
240 std::ostringstream os;
241
242 os << (n-1) << "_P_" << (r-1)
243 <<" is too big!" << std::endl;
244
245 throw std::runtime_error(os.str());
246 }
247
248 T permu = npr.value(); // n-1 P r-1
249
250 while(r) // r != 0
251 {
252 std::size_t s = m_th / permu;
253
254 auto begin = S.begin() + rr - r;
255
256 std::rotate(begin, begin+s, begin+s+1);
257
258 m_th %= permu;
259
260 --n; --r;
261
262 if( (T)n != (T)0 ) permu /= n; // n-2 P r-2
263
264 /*
265 n-1 P r-1
266 permu = ---------------- = n-2 P r-2
267 n-1
268 */
269 }
270
271 if(RemoveTails && S.size() != rr)
272 S.erase(S.begin() + rr, S.end());
273
274 return S;
275
276 }
277 // end of atomized_permutation()
278
280 template<std::size_t rr, bool RemoveTails = false,
281 typename ElementType = int, std::size_t Size = 1, typename Type = int>
282 auto atomized_permutation( std::array<ElementType, Size> S, Type m_th)
283 {
284 using T = unsigned long long;
285
286 T n = (T) S.size();
287 T r = rr;
288
289 auto remove_tails = [&S]() -> std::array<ElementType, rr>
290 {
291 std::array<ElementType, rr> SS;
292
293 for(size_t i = 0; i < rr; ++i)
294 SS[i] = std::move(S[i]);
295
296 return SS;
297 };
298
299 if( (T)r < (T)1 || (T)n < (T)1 || (T)r > (T)n)
300 {
301 if constexpr(RemoveTails && Size != rr)
302 return remove_tails();
303 else
304 return S;
305 }
306
307 auto npr = rational_number::nPr( n-1, r-1);
308
309 if(!npr.has_value())
310 {
311 std::ostringstream os;
312
313 os << (n-1) << "_P_" << (r-1)
314 <<" is too big!" << std::endl;
315
316 throw std::runtime_error(os.str());
317 }
318
319 T permu = npr.value(); // n-1 P r-1
320
321 while(r) // r != 0
322 {
323 std::size_t s = m_th / permu;
324
325 auto begin = S.begin() + rr - r;
326
327 std::rotate(begin, begin+s, begin+s+1);
328
329 m_th %= permu;
330
331 --n; --r;
332
333 if( (T)n != (T)0 ) permu /= n; // n-2 P r-2
334
335 /*
336 n-1 P r-1
337 permu = ---------------- = n-2 P r-2
338 n-1
339 */
340 }
341
342 if constexpr(RemoveTails && Size != rr)
343 return remove_tails();
344 else
345 return S;
346 }
347 // end of atomized_permutation()
348
349 // By Howard Hinnant
350 template<typename BiDiIt, typename Compare>
351 bool next_k_permutation(BiDiIt first, BiDiIt mid, BiDiIt last, Compare comp)
352 {
353 std::reverse(mid, last);
354 return std::next_permutation(first, last, comp);
355 }
356
357 // By Howard Hinnant
358 template<typename BiDiIt, typename Compare>
359 bool next_combination(BiDiIt first, BiDiIt mid, BiDiIt last, Compare comp)
360 {
361 using namespace std::placeholders;
362
363 bool result;
364 do
365 {
366 result = next_k_permutation(first, mid, last, comp);
367
368 } while (std::adjacent_find( first, mid,
369 std::bind(comp, _2, _1) ) != mid );
370 return result;
371 }
372
374 namespace hidden
375 {
377 {
378 template<typename ContainerType, typename BeginType, typename EndType>
379 ContainerType& operator()(ContainerType& container,
380 BeginType begin, EndType end) const noexcept
381 {
382 return container;
383 }
384 };
385
387 {
388 template<typename ContainerType, typename BeginType, typename EndType>
389 ContainerType& operator()(ContainerType& container,
390 BeginType begin, EndType end) const noexcept
391 {
392 container.erase(begin, end);
393 return container;
394 }
395 };
396
398 {
399 template<typename ContainerType, typename BeginType, typename EndType>
400 ContainerType& operator()(ContainerType& container,
401 BeginType begin, EndType end) const noexcept
402 {
403 std::sort(std::execution::par_unseq, begin, end);
404 return container;
405 }
406 };
407
409 {
410 template<typename ContainerType, typename BeginType, typename EndType>
411 ContainerType& operator()(ContainerType& container,
412 BeginType begin, EndType end) const noexcept
413 {
414 std::sort(std::execution::par_unseq, begin, end);
415 container.erase(container.begin(), begin);
416
417 return container;
418 }
419 };
420 }
421 // end of namespac hidden
422
427
428 template<typename ElementType, typename AllocatorType,
429 typename T1, typename T2, typename TailOperationType = hidden::st_tail_remove>
430 std::vector<ElementType, AllocatorType>
431 atomized_combination( std::vector<ElementType, AllocatorType> S, T1 r,
432 T2 m_th, TailOperationType const& tail_operation = TailOperationType{})
433 {
434 using T = std::common_type_t<T1, T2>;
435
436 if(r == 0) { return { }; }
437
438 if( r == S.size() ) return S;
439
440 T n = (T)S.size();
441
442 T rr = r;
443
444 while(r) // r != 0
445 {
446 auto ncr = rational_number::nCr( (T)n-1, (T)r-1 );
447
448 if(!ncr.has_value())
449 {
450 std::ostringstream os;
451 os << (n-1) <<"_C_" << (r-1) <<" is too big!";
452
453 throw std::runtime_error(os.str());
454 }
455
456 T count = ncr.value();
457
458 if(m_th < count) --r;
459 else
460 {
461 m_th -= count;
462
463 auto base = S.begin() + rr - r;
464
465 std::rotate(base, base + 1, S.end());
466 }
467
468 --n;
469 }
470
471 return tail_operation(S, S.begin() + rr, S.end()) ;
472 }
473}
474// end of namespace cpg::combinatorics
475
476#endif // end of file
std::atomic< int > count
Definition: 022-mutex.cpp:10
auto & endl
auto product_base(std::vector< ElementType > const &A, std::vector< ElementType > const &B)
constexpr hidden::st_tail_get tail_get
bool next_k_permutation(BiDiIt first, BiDiIt mid, BiDiIt last, Compare comp)
constexpr hidden::st_tail_no_op tail_no_op
std::vector< ElementType, AllocatorType > atomized_permutation(std::vector< ElementType, AllocatorType > S, T1 r, T2 m_th, bool RemoveTails=false)
std::vector< ElementType, AllocatorType > atomized_combination(std::vector< ElementType, AllocatorType > S, T1 r, T2 m_th, TailOperationType const &tail_operation=TailOperationType{})
bool next_combination(BiDiIt first, BiDiIt mid, BiDiIt last, Compare comp)
constexpr hidden::st_tail_sort tail_sort
constexpr hidden::st_tail_remove tail_remove
auto product(std::vector< ElementType > const &A, std::vector< ElementType > const &B, VectorTypes... tails)
auto nCr(unsigned long long n, unsigned long long r) noexcept
auto nPr(unsigned long long n, unsigned long long r=1) noexcept
constexpr auto reverse(sequence< ms... > mm, sequence< rs... >)
Definition: cpg_types.hpp:4248
enable_if_all_in_list_t< types::type_list_t< Type1, Type2 >, integral_list_t, ReturnType > npr(Type1 nn, Type2 rr)
Definition: tpf_ncrnpr.hpp:428
enable_if_all_in_list_t< types::type_list_t< Type1, Type2 >, integral_list_t, ReturnType > ncr(Type1 nn, Type2 rr)
Definition: tpf_ncrnpr.hpp:390
ContainerType< EleType > sort(ContainerType< EleType, Types... > container, sort_order order=sort_order::ascending, sort_method method=sort_method::size)
Definition: tpf_set.hpp:438
ContainerType & operator()(ContainerType &container, BeginType begin, EndType end) const noexcept
ContainerType & operator()(ContainerType &container, BeginType begin, EndType end) const noexcept
ContainerType & operator()(ContainerType &container, BeginType begin, EndType end) const noexcept
ContainerType & operator()(ContainerType &container, BeginType begin, EndType end) const noexcept