C++ Library Extensions 2022.12.09
To help learn modern C++ programming
tpf_ncrnpr.hpp
Go to the documentation of this file.
1
11#ifndef _TPF_NCRNPR_HPP
12#define _TPF_NCRNPR_HPP
13
14#ifndef NOMINMAX
15#define NOMINMAX
16#endif
17
18#ifdef _MSVC_LANG
19 #if _MSVC_LANG < 201703L
20 #error This libary requires C++17 Standard (Visual Studio 2017).
21 #endif
22#else
23
24 #if __cplusplus < 201703
25 #error This library requires C++17 Standard (GNU g++ version 8.0 or clang++ version 8.0 above)
26 #endif // end of __cplusplus
27
28#endif // end of _MSVC_LANG
29
30#include <tpf_euclidean.hpp>
31#include <iostream>
32#include <sstream>
33#include <list>
34#include <functional>
35#include <iterator>
36#include <future>
37#include <vector>
38#include <algorithm>
39#include <tpf_safe_type.hpp>
40
41#if defined(_GLIBCXX_PARALLEL)
42 #include <parallel/algorithm>
43#elif defined (_MSC_VER)
44 // C++2a Standard header file for Parallel Algorithm
45 #include <execution>
46 #include <ppl.h>
47#elif defined (__ICL)
48 // C++2a Standard header file for Parallel Algorithm
49 #include <execution>
50 #include <tbb/parallel_for.h>
51#endif
52
57namespace tpf
58{
63 namespace ncrnpr
64 {
65 using namespace types;
66 using namespace euclidean;
67
76 template<template<typename, typename...> class ContainerType,
77 typename EleType, typename... Types>
78 int sgn(const ContainerType<EleType, Types...>& cntr)
79 {
80 EleType count = 0, cntr_i;
81 EleType size = cntr.size();
82 for(EleType i = 1; i < size; ++i)
83 {
84 cntr_i = cntr[i];
85
86 for(EleType j=0; j < i; ++j)
87 if(cntr_i < cntr[j]) ++count;
88 }
89
90 return (count%2 ? -1:1);
91 }
92
93 class range_t: public std::pair<size_t, size_t>
94 {
95 public:
96 using index_t = size_t;
97 using base_t = std::pair<size_t, size_t>;
98 public:
99 size_t begin() { return this->first; }
100 size_t end() { return this->second; }
101 size_t cbegin() const { return this->first; }
102 size_t cend() const { return this->second; }
103
104 base_t& base() { return static_cast<base_t&>(*this); }
105 const base_t& base() const { return static_cast<const base_t&>(*this); }
106
107 range_t() = default;
108 range_t(const range_t&) = default;
109 range_t& operator = (const range_t&) = default;
110 range_t(range_t&&) = default;
111 range_t& operator=(range_t&&) = default;
112
113 template<typename Type1, typename Type2>
114 range_t(Type1 start, Type2 end):
115 std::pair<size_t, size_t>{(index_t)start, (index_t)end}
116 { }
117
118 std::string str() const
119 {
120 std::ostringstream os;
121
122 os << "[" << this->first << ", "
123 << this->second << ")("
124 << (this->second - this->first)<<")";
125
126 return os.str();
127 }
128
129 std::wstring wstr() const
130 {
131 std::wostringstream os;
132
133 os << L"[" << this->first << L", "
134 << this->second << L")("
135 << (this->second - this->first)<<L")";
136
137 return os.str();
138 }
139
140 friend std::ostream& operator<<(std::ostream& os,
141 const range_t& range)
142 {
143 os << range.str();
144 return os;
145 }
146 };
147
148 using range_vector_t = std::vector<range_t>;
149
150 /*
151 st ed
152 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
153
154 minimum span = 3; [1, 5), [5, 8), [8, 11)
155
156 1, 2, 3, 4, 5 -> [1, 5) : 4
157 5, 6, 7, 8 -> [5, 8) : 3
158 8, 9, 10, 11 -> [8, 11): 3
159 */
160
172 template<typename SpanType, typename StartType, typename EndType>
173 range_vector_t split_range_span(SpanType min_span, StartType st, EndType ed)
174 {
175 size_t dist = (size_t)ed - (size_t)st;
176 size_t rnd = (size_t)dist % (size_t)min_span;
177 size_t count = (size_t)dist / (size_t)min_span;
178
179 range_vector_t rng;
180
181 if(dist <= min_span)
182 {
183 rng.emplace_back(range_t{(size_t)st, (size_t)ed});
184 return rng;
185 }
186 else if (rnd == 0)
187 {
188 size_t prev = (size_t)st;
189 for (size_t i = 0; i < count; ++i)
190 {
191 rng.emplace_back(range_t{prev, prev + min_span});
192 prev += min_span;
193 }
194 return rng;
195 }
196 else
197 {
198 if (count >= rnd)
199 {
200 size_t span1 = min_span + 1;
201
202 size_t prev = (size_t)st;
203 for (size_t i = 0; i < rnd; ++i)
204 {
205 rng.emplace_back(range_t(prev, prev + span1));
206 prev += span1;
207 }
208
209 count = count - (size_t)rnd;
210 for (size_t i = 0; i < count; ++i)
211 {
212 rng.emplace_back(range_t{prev, prev + min_span});
213 prev += min_span;
214 }
215 return rng;
216 }
217 else
218 {
219 return split_range_span(count, st, ed);
220 }
221 }
222 }
223
224 template<typename CountType, typename StartType, typename EndType>
225 range_vector_t split_range_count(CountType count, StartType st, EndType ed)
226 {
227 size_t dist = (size_t)ed - (size_t)st;
228 size_t span = (size_t)dist / (size_t)count;
229 size_t rnd = (size_t)dist % (size_t)count;
230
231 range_vector_t rng;
232
233 if (rnd == 0)
234 {
235 size_t prev = st;
236 for (size_t i = 0; i < count; ++i)
237 {
238 rng.emplace_back(range_t{prev, prev + span});
239 prev += span;
240 }
241
242 return rng;
243 }
244 else
245 {
246 size_t span1 = span + (size_t)1;
247
248 size_t prev = st;
249 for (size_t i = 0; i < rnd; ++i)
250 {
251 rng.emplace_back(range_t{prev, prev + span1});
252 prev += span1;
253 }
254
255 // rnd = dist % count;
256 // rnd cannot be greater than count
257 count = count - rnd;
258 for (size_t i = 0; i < count; ++i)
259 {
260 rng.emplace_back(range_t{prev, prev + span});
261 prev += span;
262 }
263
264 return rng;
265 }
266 }
267
268 template<typename NumberType,
269 typename = std::enable_if_t<is_unsigned_integer_v<NumberType>>>
271 {
272 public:
273 using number_t = NumberType;
274
275 private:
276 number_t m_p{0}; // numerator
277 number_t m_q{1}; // denominator
278
280 m_p{p}, m_q{q} { }
281
282 public:
285
286 template<typename Type>
287 operator Type() const { return (Type)m_p / (Type)m_q; }
288
290 m_p{p}, m_q{q}
291 {
292 euclidean::reduce(m_p, m_q);
293 }
294
296
298
300 {
301 /* m_p n
302 ------- x n => m_p x -------
303 m_q m_q
304 */
305
306 euclidean::reduce(n, m_q);
307
308 // m_p *= n;
309 m_p = safe_type::safe_mul(m_p, n);
310
311 return *this;
312 }
313
315 {
316 /* m_p r.m_p m_p r.m_p
317 ------- x -------- => ------- x --------
318 m_q r.m_q r.m_q m_q
319 */
320
321 euclidean::reduce(m_p, r.m_q);
322 euclidean::reduce(r.m_p, m_q);
323
324 // m_p *= r.m_p;
325 m_p = safe_type::safe_mul(m_p, r.m_p);
326
327 // m_q *= r.m_q;
328 m_q = safe_type::safe_mul(m_q, r.m_q);
329
330 return *this;
331 }
332
333 template<typename RationalType>
334 friend decltype(auto)
335 operator*(RationalType&& r, number_t n)
336 {
338 remove_cv_ref_t<RationalType>>, "r should be rational number");
339
340 if constexpr(std::is_rvalue_reference_v<decltype(r)>)
341 {
342 r *= n; // throws if overflow
343
344 return std::forward<RationalType>(r);
345 }
346 else
347 {
348 auto rlt = r; rlt *= n; // throws if overflow
349 return rlt;
350 }
351 }
352
353 template<typename RationalType1, typename RationalType2>
354 friend decltype(auto)
355 operator*(RationalType1&& r1, RationalType1&& r2)
356 {
357 /* m_p r.m_p m_p r.m_p
358 ------- x -------- => ------- x --------
359 m_q r.m_q r.m_q m_q
360 */
361
362 if constexpr(std::is_rvalue_reference_v<decltype(r1)>)
363 {
364 r1 *= r2; // throws if overflow
365
366 return std::forward<RationalType1>(r1);
367 }
368 else if constexpr(std::is_rvalue_reference_v<decltype(r2)>)
369 {
370 r2 *= r1; // throws if overflow
371 return std::forward<RationalType2>(r2);
372 }
373 else
374 {
375 auto r = r1; r *= r2; // throws if overflow
376 return r;
377 }
378 }
379
380 friend std::ostream& operator<<(std::ostream& os, const simple_positive_rational& r)
381 {
382 os << "(" << r.m_p << ", " << r.m_q << ")";
383 return os;
384 }
385
386 }; // end of class simple_positive_rational
387
388 template<typename Type1, typename Type2, typename ReturnType = unsigned long long>
389 enable_if_all_in_list_t<types::type_list_t<Type1, Type2>, integral_list_t, ReturnType>
390 ncr(Type1 nn, Type2 rr)
391 {
392 size_t r = (size_t)rr; size_t n = (size_t)nn;
393
394 /*
395 nPr n x (n-1) x ... x (n-r+1)
396 nCr x r ! = nPr; => nCr = ------- = -----------------------------
397 r! r x (r-1) x ... x 1
398 */
399
400 if (r == 0 || n == r)
401 {
402 return 1;
403 }
404 else if (r == 1 || r == (n - 1))
405 {
406 return n;
407 }
408 else
409 {
410 using rational_t = simple_positive_rational<ReturnType>;
411
412 if(r > (n-r) ) r = n-r;
413
414 rational_t rlt{(ReturnType)n, (ReturnType)r};
415
416 for(ReturnType i = 1; i < (ReturnType)(r); ++i)
417 {
418 rlt *= rational_t((ReturnType)n - i, (ReturnType)r - i);
419 }
420
421 return rlt;
422 }
423
424 } // end of function ncr
425
426 template<typename Type1, typename Type2, typename ReturnType = unsigned long long>
427 enable_if_all_in_list_t<types::type_list_t<Type1, Type2>, integral_list_t, ReturnType>
428 npr(Type1 nn, Type2 rr)
429 {
430 size_t n = (size_t)nn; size_t r=(size_t)rr;
431
432 if (r == 0)
433 return 1;
434 else if (r == 1)
435 return n;
436 else
437 {
438 ReturnType rlt = n;
439
440 for (ReturnType i = 1; i < (ReturnType)r; ++i)
441 {
442 // rlt *= ((ReturnType)n - i);
443 rlt = safe_type::safe_mul(rlt, ((ReturnType)n - i));
444 }
445
446 return rlt;
447 }
448 }
449
450 template<typename Type, typename ReturnType = unsigned long long>
451 enable_if_in_list_t<Type, integral_list_t, ReturnType>
452 fact(Type n)
453 {
454 return npr(n, n);
455 }
456
458 {
459 public:
461 using m_th_t = number_t;
463
465
466 protected:
467 mutable number_t m_n{}, m_r{}, m_ncr{1};
468
469 template<typename Type>
470 void offset_nr(Type offset)
471 {
472 if (offset < 0)
473 {
474 while (offset < 0)
475 {
476 // WARING: the following does not work,
477 // because this->m_ncr is NOT a rational number
478 // this->m_ncr *= rational_t{this->m_r--, m_n--};
479
480 this->m_ncr = rational_t{this->m_r--, m_n--} * this->m_ncr;
481
482 ++offset;
483 }
484 }
485 else if (offset > 0)
486 {
487 while (offset > 0)
488 {
489 // WARING: the following does not work,
490 // because this->m_ncr is NOT a rational number
491 // this->m_ncr *= rational_t{++m_n, ++m_r};
492
493 this->m_ncr = rational_t{++m_n, ++m_r} * this->m_ncr;
494
495 --offset;
496 }
497 }
498 }
499
500 template<typename Type>
501 void offset_n(Type offset)
502 {
503 if (offset > 0)
504 {
505 while (offset > 0)
506 {
507 // WARING: the following does not work,
508 // because this->m_ncr is NOT a rational number
509 // this->m_ncr *= rational_t{m_n + 1, m_n - m_r + 1};
510
511 this->m_ncr = rational_t{m_n + 1, m_n - m_r + 1} * this->m_ncr;
512
513 ++m_n; --offset;
514 }
515 }
516 else if (offset < 0)
517 {
518 while (offset < 0)
519 {
520 // WARING: the following does not work,
521 // because this->m_ncr is NOT a rational number
522 // this->m_ncr *= rational_t{m_n - m_r, m_n};
523
524 this->m_ncr = rational_t{m_n - m_r, m_n} * this->m_ncr;
525
526 --m_n; ++offset;
527 }
528 }
529 }
530
531 template<typename Type>
532 void offset_r(Type offset)
533 {
534 if (offset > 0)
535 {
536 while (offset > 0)
537 {
538 // WARING: the following does not work,
539 // because this->m_ncr is NOT a rational number
540 // this->m_ncr *= rational_t{m_n - m_r, m_r + 1};
541
542 this->m_ncr = rational_t{m_n - m_r, m_r + 1} * this->m_ncr;
543
544 ++m_r; --offset;
545 }
546 }
547 else if (offset < 0)
548 {
549 while (offset < 0)
550 {
551 // WARING: the following does not work,
552 // because this->m_ncr is NOT a rational number
553 // this->m_ncr *= rational_t{m_r, m_n - m_r + 1};
554
555 this->m_ncr = rational_t{m_r, m_n - m_r + 1} * this->m_ncr;
556
557 --m_r; ++offset;
558 }
559 }
560 }
561
562 public:
563
564 combination(): m_n{0}, m_r{0}, m_ncr{1} { }
565 combination(const combination&) = default;
567
568 template<typename Type>
570 m_ncr{ 1 } { }
571
572 template<typename Type1, typename Type2>
573 combination(Type1 n, Type2 r): m_n{(number_t)n}, m_r{(number_t)r},
574 m_ncr{ ncr(m_n, m_r) } { }
575
576 number_t operator()()const { return this->m_ncr; }
577
578 template<typename Type1, typename Type2>
579
580 number_t reset(Type1 n = Type1{}, Type2 r = Type2{})
581 {
582 this->m_n = {(number_t)n}; this->m_r = {(number_t)r};
583 this->m_ncr = ncr((number_t)n, (number_t)r);
584
585 return this->m_ncr;
586 }
587
588 template<typename Type>
590 {
591 signed_m_th_t offset = (signed_m_th_t)r - (signed_m_th_t)this->m_r;
592
593 if(offset == 0)
594 return this->m_ncr;
595 else
596 {
597 this->offset_r(offset);
598 return this->m_ncr;
599 }
600 }
601
602 template<typename Type>
604 {
605 signed_m_th_t offset = (signed_m_th_t)this->m_n - (signed_m_th_t)n;
606 if(offset != 0)
607 return this->m_ncr;
608 else
609 {
610 this->offset_n(offset);
611 return this->m_ncr;
612 }
613 }
614
616 {
617 // WARING: the following does not work,
618 // because this->m_ncr is NOT a rational number
619 // this->m_ncr *= rational_t{m_r--, m_n--};
620
621 this->m_ncr = rational_t{m_r--, m_n--} * this->m_ncr;
622
623 return this->m_ncr;
624 }
625
627 {
628 // WARING: the following does not work,
629 // because this->m_ncr is NOT a rational number
630 // this->m_ncr *= rational_t{++m_n, ++m_r};
631
632 this->m_ncr = rational_t{++m_n, ++m_r} * this->m_ncr;
633
634 return this->m_ncr;
635 }
636
638 {
639 // WARING: the following does not work,
640 // because this->m_ncr is NOT a rational number
641 // this->m_ncr *= rational_t{m_n - m_r, m_r + 1};
642
643 this->m_ncr = rational_t{m_n - m_r, m_r + 1} * this->m_ncr;
644
645 // we should do this, because compiler
646 // may evaluate on the right handside first
647 ++m_r; return this->m_ncr;
648 }
649
651 {
652 // WARING: the following does not work,
653 // because this->m_ncr is NOT a rational number
654 // this->m_ncr *= rational_t{m_r, m_n - m_r + 1};
655
656 this->m_ncr = rational_t{m_r, m_n - m_r + 1} * this->m_ncr;
657
658 // we should do this, because compiler
659 // may evaluate on the right handside first
660 --m_r;
661
662 return this->m_ncr;
663 }
664
666 {
667 // WARING: the following does not work,
668 // because this->m_ncr is NOT a rational number
669 // this->m_ncr *= rational_t{m_n + 1, m_n - m_r + 1};
670 this->m_ncr = rational_t{m_n + 1, m_n - m_r + 1} * this->m_ncr;
671
672 // we should do this, because compiler
673 // may evaluate on the right handside first
674 ++m_n;
675
676 return this->m_ncr;
677 }
678
680 {
681 // WARING: the following does not work,
682 // because this->m_ncr is NOT a rational number
683 // this->m_ncr *= rational_t{m_n - m_r, m_n};
684 this->m_ncr = rational_t{m_n - m_r, m_n} * this->m_ncr;
685
686 // we should do this, because compiler
687 // may evaluate on the right handside first
688 --m_n;
689
690 return this->m_ncr;
691 }
692
693 template<typename Type1, typename Type2>
694 number_t operator() (Type1 n, Type2 r)
695 {
696 this->m_n = (number_t)n;
697 this->m_r = (number_t)r;
698
699 this->m_ncr = ncr(m_n, m_r);
700
701 return this->m_ncr;
702 }
703
704 template<typename Type>
705 operator Type() const { return (Type)this->m_ncr; }
706
707 friend std::ostream&
708 operator<<(std::ostream& os, const combination& cb)
709 {
710 os << "{" << cb.m_n <<" C "
711 << cb.m_r << " = " << cb.m_ncr << "}";
712 return os;
713 }
714
715 }; // end of class combination
716
717 // returns m_th subset by selecting r elements from
718 // the set from_set with n elements (from_set.size())
719 // std::deque<Type> ele should be in order
720 // ele = { 0, 1, 2, 3 }
721 template<template<typename, typename...> class SetContainer = std::vector, typename... ContainerTails,
722 typename MthType = combination::m_th_t, typename EleType = int, typename SelectCountType = size_t,
723 typename ReturnType = std::vector<EleType>>
724 ReturnType enumerate_combination(combination cmb, MthType m_th,
725 SetContainer<EleType, ContainerTails...> from_set, SelectCountType select_count)
726 {
727 constexpr auto is_from_set_vector =
728 types::is_same_template_v<SetContainer<EleType, ContainerTails...>,
729 std::vector<EleType>>;
730
731 constexpr auto is_return_vector =
732 types::is_same_template_v<ReturnType, std::vector<EleType>>;
733
734 size_t set_size = from_set.size();
735
736 ReturnType selected_set;
737
738 if constexpr(is_from_set_vector)
739 reverse_order_in_place(from_set);
740
741 if constexpr(is_return_vector)
742 selected_set.reserve((size_t)select_count);
743 do
744 {
745 if (select_count == 0)
746 {
747 break;
748 }
749 else if ((size_t)select_count == set_size)
750 {
751 append_to_container<is_from_set_vector>(selected_set, std::move(from_set));
752 break;
753 }
754 else
755 {
756 if (m_th < cmb())
757 {
758 if constexpr(is_from_set_vector)
759 emplace_back(selected_set, pop_back(from_set));
760 else
761 emplace_back(selected_set, pop_front(from_set));
762
763 --select_count; cmb.decrement_nr();
764 }
765 else
766 {
767 if constexpr(is_from_set_vector)
768 pop_back(from_set);
769 else
770 pop_front(from_set);
771
772 m_th -= cmb(); cmb.decrement_n();
773 }
774
775 --set_size;
776 }
777
778 } while (true);
779
780 return selected_set;
781 }
782
783 // returns m_th subset by selecting r elements from
784 // the set from_set with n elements (from_set.size())
785 // std::deque<Type> ele should be in order
786 // ele = { 0, 1, 2, 3 }
787 template<template<typename, typename...> class ReturnContainer = std::vector,
788 template<typename, typename...> class SetContainer = std::list, typename... ContainerTails,
789 typename MthType = combination::m_th_t, typename EleType = int, typename SelectCountType = size_t,
790 typename SetTagType = tpf::set_tag<ReturnContainer, EleType>,
791 typename ReturnType = tpf::duet_set_t<SetTagType>>
793 SetContainer<EleType, ContainerTails...> from_set, SelectCountType select_count)
794 {
795 constexpr auto is_from_set_vector =
796 types::is_same_template_v<SetContainer<EleType, ContainerTails...>, std::vector<EleType>>;
797
798 constexpr auto is_return_vector =
799 types::is_same_template_v<ReturnContainer<EleType>, std::vector<EleType>>;
800
801 size_t set_size = from_set.size();
802
803 ReturnType duet_set;
804 auto& [selected_set, complement_set] = duet_set;
805
806 if constexpr(is_from_set_vector)
807 reverse_order_in_place(from_set);
808
809 if constexpr(is_return_vector)
810 {
811 selected_set.reserve((size_t)select_count);
812 complement_set.reserve((size_t)set_size - (size_t)select_count);
813 }
814
815 do
816 {
817 if (select_count == 0)
818 {
819 append_to_container<is_from_set_vector>(complement_set, std::move(from_set));
820
821 break;
822 }
823 else if ((size_t)select_count == set_size)
824 {
825 append_to_container<is_from_set_vector>(selected_set, std::move(from_set));
826
827 break;
828 }
829 else
830 {
831 if (m_th < cmb())
832 {
833 if constexpr(is_from_set_vector)
834 emplace_back(selected_set, pop_back(from_set));
835 else
836 emplace_back(selected_set, pop_front(from_set));
837
838 --select_count; cmb.decrement_nr();
839 }
840 else
841 {
842 if constexpr(is_from_set_vector)
843 emplace_back(complement_set, pop_back(from_set));
844 else
845 emplace_back(complement_set, pop_front(from_set));
846
847 m_th -= cmb(); cmb.decrement_n();
848 }
849
850 --set_size;
851 }
852
853 } while (true);
854
855 return duet_set;
856 }
857
858 // returns m_th subset by selecting r elements from
859 // the set from_set with n elements (from_set.size())
860 // std::deque<Type> ele should be in order
861 // ele = { 0, 1, 2, 3 }
862 template<template<typename, typename...> class ReturnContainer = std::vector,
863 typename MthType = combination::m_th_t,
864 typename SetSizeType = size_t, typename SelectCountType = size_t,
865 typename SetTagType = tpf::set_tag<ReturnContainer, int>,
866 typename ReturnType = tpf::duet_set_t<SetTagType>>
867 auto enumerate_combination_and_complement(MthType m_th, SetSizeType set_size, SelectCountType select_count)
868 {
869 std::vector<int> from_set;
870
871 size_t size = (size_t)set_size;
872
873 from_set.reserve(size);
874
875 for(size_t i = 0; i < size; ++i)
876 from_set.emplace_back((int)i);
877
878 ncrnpr::combination cmb{size-1, select_count-1};
879
880 return enumerate_combination_and_complement(cmb, m_th, from_set, select_count);
881 }
882
884 // returns m_th subset by selecting r elements from
885 // the set from_set with n elements (from_set.size())
886 // std::deque<Type> ele should be in order
887 // ele = { 0, 1, 2, 3 }
888 // template<template<typename, typename...> class ReturnContainer = std::vector,
889 // typename SetSizeType = size_t, typename SelectCountType = size_t,
890 // typename SetTagType = tpf::set_tag<ReturnContainer, int>,
891 // typename ReturnType = tpf::set_of_duets_t<SetTagType>>
892 // auto enumerate_combinations_and_offsets_indices(SetSizeType set_size, SelectCountType select_count);
893
894 template<template<typename, typename...> class ReturnContainer = std::vector,
895 template<typename, typename...> class SetContainer = std::list, typename... ContainerTails,
896 typename MthType = combination::m_th_t, typename EleType = int, typename SelectCountType = size_t,
897 typename SetTagType = tpf::set_tag<ReturnContainer, EleType>,
898 typename ReturnType = tpf::set_of_duets_t<SetTagType>>
899 auto enumerate_combinations_and_offsets(SetContainer<EleType, ContainerTails...> from_set,
900 SelectCountType select_count = tpf::InvalidIndex)
901 {
902 size_t set_size = from_set.size();
903
904 using m_th_t = combination::m_th_t;
905
906 ReturnType sets;
907
908 if(select_count != tpf::InvalidIndex)
909 {
910 m_th_t max_m_th = ncr((m_th_t)set_size, (m_th_t)select_count);
911 sets.reserve(max_m_th);
912
913 ncrnpr::combination cmb{set_size-1, select_count-1};
914
915 for(m_th_t m_th = 0; m_th < max_m_th; ++m_th)
916 sets.emplace_back(enumerate_combination_and_complement<ReturnContainer>
917 (cmb, m_th, from_set, (size_t)select_count));
918
919 return sets;
920 }
921 else
922 {
923 sets.reserve((size_t)tpf::two_power_n(set_size));
924
925 for(size_t r = 0; r <= set_size; ++r)
926 {
927 m_th_t m_th_max = ncr((m_th_t)set_size, (m_th_t)r);
928
929 ncrnpr::combination cmb{set_size-1, r-1};
930
931 for(m_th_t m_th = 0; m_th < m_th_max; ++m_th)
932 sets.emplace_back(enumerate_combination_and_complement<ReturnContainer>
933 (cmb, m_th, from_set, (size_t)r));
934 }
935
936 return sets;
937 }
938 }
939
941
942 // returns m_th subset by selecting r elements from
943 // the set from_set with n elements (from_set.size())
944 // std::vector<int> ele should be in order
945 // ele = { 0, 1, 2, 3 }
946 template<template<typename, typename...> class ReturnContainer = std::vector,
947 typename MthType = combination::m_th_t, typename SelectCountType = size_t,
948 typename SetTagType = tpf::set_tag<ReturnContainer, int>,
949 typename ReturnType = tpf::duet_set_t<SetTagType>>
951 std::vector<int> from_set, SelectCountType select_count)
952 {
953 constexpr auto is_return_vector =
954 types::is_same_template_v<ReturnContainer<int>, std::vector<int>>;
955
956 ReturnType duet_set;
957 auto& [selected_set, complement_set] = duet_set;
958
959 size_t set_size = from_set.size();
960
961 if constexpr(is_return_vector)
962 {
963 selected_set.reserve((size_t)select_count);
964 complement_set.reserve((size_t)set_size - (size_t)select_count);
965 }
966
967 // combination cmb(set_size - 1, select_count - 1);
968
969 do
970 {
971 if (select_count <= 0)
972 {
973 append_to_container<true>(complement_set, std::move(from_set));
974
975 break;
976 }
977 else if ((size_t)select_count == set_size)
978 {
979 append_to_container<true>(selected_set, std::move(from_set));
980
981 break;
982 }
983 else
984 {
985 if (m_th < cmb())
986 {
987 emplace_back(selected_set, pop_back(from_set));
988 --select_count; cmb.decrement_nr();
989 }
990 else
991 {
992 emplace_back(complement_set, pop_back(from_set));
993 m_th -= cmb(); cmb.decrement_n();
994 }
995
996 --set_size;
997 }
998
999 } while (true);
1000
1001 return duet_set;
1002 }
1003
1004
1005 // returns m_th subset by selecting r elements from
1006 // the set from_set with n elements (from_set.size())
1007 // std::deque<Type> ele should be in order
1008 // ele = { 0, 1, 2, 3 }
1009 template<template<typename, typename...> class ReturnContainer = std::vector,
1010 typename SetSizeType = size_t, typename SelectCountType = size_t,
1011 typename SetTagType = tpf::set_tag<ReturnContainer, int>,
1012 typename ReturnType = tpf::set_of_duets_t<SetTagType>>
1014 SelectCountType select_count = tpf::InvalidIndex)
1015 {
1016 std::vector<int> from_set;
1017 from_set.reserve(set_size);
1018
1019 for(size_t i = set_size-1; i != 0; --i)
1020 from_set.emplace_back((int)i);
1021
1022 from_set.emplace_back(0);
1023
1024 using m_th_t = combination::m_th_t;
1025
1026 ReturnType sets;
1027
1028 if(select_count != tpf::InvalidIndex)
1029 {
1030 m_th_t m_th_max = ncr(set_size, select_count);
1031 sets.reserve(m_th_max);
1032
1033 ncrnpr::combination cmb{set_size-1, select_count-1};
1034
1035 for(m_th_t m_th = 0; m_th < m_th_max; ++m_th)
1036 sets.emplace_back(enumerate_combinations_and_offsets_indices<ReturnContainer>
1037 (cmb, m_th, from_set, select_count));
1038
1039 return sets;
1040 }
1041 else
1042 {
1043 sets.reserve((size_t)tpf::two_power_n(set_size));
1044
1045 for(size_t r = 0; r <= set_size; ++r)
1046 {
1047 m_th_t m_th_max = ncr((m_th_t)set_size, (m_th_t)r);
1048
1049 ncrnpr::combination cmb{set_size-1, r-1};
1050
1051 for(m_th_t m_th = 0; m_th < m_th_max; ++m_th)
1052 sets.emplace_back(enumerate_combinations_and_offsets_indices<ReturnContainer>
1053 (cmb, m_th, from_set, r));
1054 }
1055
1056 return sets;
1057 }
1058 }
1059
1060 // returns m_th subset by selecting r elements from
1061 // the set from_set with n elements (from_set.size())
1062 // std::deque<Type> ele should be in order
1063 // ele = { 0, 1, 2, 3 }
1064 template<template<typename, typename...> class ReturnContainer = std::vector,
1065 typename SetSizeType = size_t, typename SelectCountType = size_t,
1066 typename SetTagType = tpf::set_tag<ReturnContainer, int>,
1067 typename ReturnType = tpf::set_of_duets_t<SetTagType>>
1068 auto enumerate_combination_including_indices(std::vector<int> include_set,
1069 SetSizeType set_size, SelectCountType select_count = tpf::InvalidIndex)
1070 {
1071 std::sort(include_set.begin(),
1072 include_set.end(), std::greater<int>{});
1073
1074 std::vector<int> from_set;
1075
1076 for(size_t i = set_size-1; i != 0; --i)
1077 {
1078 if(!std::binary_search(include_set.crbegin(), include_set.crend(), i))
1079 from_set.emplace_back(i);
1080 }
1081
1082 if(!std::binary_search(include_set.crbegin(), include_set.crend(), 0))
1083 from_set.emplace_back(0);
1084
1085 using m_th_t = combination::m_th_t;
1086
1087 ReturnType sets;
1088
1089 if(select_count != tpf::InvalidIndex)
1090 {
1091 size_t choice_count = select_count - include_set.size();
1092 m_th_t m_th_max = ncr(from_set.size(), choice_count);
1093 sets.reserve(m_th_max);
1094
1095 ncrnpr::combination cmb{from_set.size()-1, choice_count-1};
1096
1097 for(m_th_t m_th = 0; m_th < m_th_max; ++m_th)
1098 sets.emplace_back(enumerate_combinations_and_offsets_indices<ReturnContainer>
1099 (cmb, (combination::m_th_t)m_th, from_set, (size_t)choice_count));
1100
1101 for(auto& ss: sets)
1102 {
1103 auto&[v, c] = ss;
1104
1105 types::append_to_container<false>(v, include_set);
1106 std::sort(v.begin(), v.end());
1107 v.erase(std::unique(v.begin(), v.end()), v.end());
1108 }
1109
1110 return sets;
1111 }
1112 else
1113 {
1114 set_size = from_set.size();
1115 sets.reserve((size_t)tpf::two_power_n(set_size));
1116
1117 for(size_t r = 0; r <= set_size; ++r)
1118 {
1119 m_th_t m_th_max = ncr((m_th_t)set_size, (m_th_t)r);
1120
1121 ncrnpr::combination cmb{set_size-1, r-1};
1122
1123 for(m_th_t m_th = 0; m_th < m_th_max; ++m_th)
1124 sets.emplace_back(enumerate_combinations_and_offsets_indices<ReturnContainer>
1125 (cmb, (combination::m_th_t)m_th, from_set, (size_t)r));
1126 }
1127
1128 for(auto& ss: sets)
1129 {
1130 auto&[v, c] = ss;
1131
1132 types::append_to_container<false>(v, include_set);
1133 std::sort(v.begin(), v.end());
1134 v.erase(std::unique(v.begin(), v.end()), v.end());
1135 }
1136
1137 return sets;
1138 }
1139 }
1140
1141 // returns m_th subset by selecting r elements from
1142 // the set from_set with n elements (from_set.size())
1143 // std::deque<Type> ele should be in order
1144 // ele = { 0, 1, 2, 3 }
1145 template<template<typename, typename...> class ReturnContainer = std::vector,
1146 typename SetSizeType = size_t, typename SelectCountType = size_t,
1147 typename SetTagType = tpf::set_tag<ReturnContainer, int>,
1148 typename ReturnType = tpf::set_of_duets_t<SetTagType>>
1149 auto enumerate_combination_excluding_indices(std::vector<int> exclude_set,
1150 SetSizeType set_size, SelectCountType select_count = tpf::InvalidIndex)
1151 {
1152 std::sort(exclude_set.begin(),
1153 exclude_set.end(), std::greater<int>{});
1154
1155 std::vector<int> from_set;
1156
1157 for(size_t i = set_size-1; i != 0; --i)
1158 {
1159 if(!std::binary_search(exclude_set.crbegin(), exclude_set.crend(), i))
1160 from_set.emplace_back(i);
1161 }
1162
1163 if(!std::binary_search(exclude_set.crbegin(), exclude_set.crend(), 0))
1164 from_set.emplace_back(0);
1165
1166 using m_th_t = combination::m_th_t;
1167
1168 ReturnType sets;
1169
1170 if(select_count != tpf::InvalidIndex)
1171 {
1172 m_th_t m_th_max = ncr(from_set.size(), select_count);
1173 sets.reserve(m_th_max);
1174
1175 ncrnpr::combination cmb{from_set.size()-1, select_count-1};
1176
1177 for(m_th_t m_th = 0; m_th < m_th_max; ++m_th)
1178 sets.emplace_back(enumerate_combinations_and_offsets_indices<ReturnContainer>
1179 (cmb, (combination::m_th_t)m_th, from_set, (size_t)select_count));
1180
1181 for(auto& ss: sets)
1182 {
1183 auto&[v, c] = ss;
1184
1185 types::append_to_container<false>(c, exclude_set);
1186 std::sort(c.begin(), c.end());
1187 v.erase(std::unique(c.begin(), c.end()), c.end());
1188 }
1189
1190 return sets;
1191 }
1192 else
1193 {
1194 set_size = from_set.size();
1195 sets.reserve((size_t)tpf::two_power_n(set_size));
1196
1197 for(size_t r = 0; r <= set_size; ++r)
1198 {
1199 m_th_t m_th_max = ncr((m_th_t)set_size, (m_th_t)r);
1200
1201 ncrnpr::combination cmb{ set_size-1, r-1 };
1202
1203 for(m_th_t m_th = 0; m_th < m_th_max; ++m_th)
1204 sets.emplace_back(enumerate_combinations_and_offsets_indices<ReturnContainer>
1205 (cmb, (combination::m_th_t)m_th, from_set, (size_t)r));
1206 }
1207
1208 for(auto& ss: sets)
1209 {
1210 auto&[v, c] = ss;
1211
1212 types::append_to_container<false>(c, exclude_set);
1213 std::sort(c.begin(), c.end());
1214 v.erase(std::unique(c.begin(), c.end()), c.end());
1215 }
1216
1217 return sets;
1218 }
1219 }
1220
1222 {
1223 public:
1225
1226 protected:
1227 mutable number_t m_n{}, m_r{};
1228 mutable number_t m_npr{1};
1229
1230 void reset()
1231 {
1232 this->m_n = {}; this->m_r = {};
1233 this->m_npr = {1};
1234 }
1235
1236 public:
1237 permutation(): m_n{}, m_r{}, m_npr{1} { }
1238
1239 template<typename Type1, typename Type2>
1240 permutation(Type1 n, Type2 r): m_n{(number_t)n}, m_r{(number_t)r},
1241 m_npr{npr(m_n, m_r)} { }
1242
1243 permutation(const permutation&) = default;
1245
1246 number_t operator()() const { return this->m_npr;}
1247
1248 template<typename Type1, typename Type2>
1249 number_t operator()(Type1 n, Type2 r)
1250 {
1251 this->m_n = (number_t)n; this->m_r = (number_t)r;
1252 this->m_npr = npr(this->m_n, this->m_r);
1253
1254 return this->m_npr;
1255 }
1256
1257 template<typename Type>
1258 operator Type() const { return (Type)this->m_npr; }
1259
1260 friend std::ostream&
1261 operator<<(std::ostream& os, const permutation& p)
1262 {
1263 os << "{" << p.m_n <<" P "
1264 << p.m_r << " = " << p.m_npr << "}";
1265 return os;
1266 }
1267 };
1268
1269 // this is the fastest and most efficient
1270 template<typename RType, typename MType>
1271 std::vector<int> enumerate_permutation(std::vector<int> e, RType r, MType m_th)
1272 {
1273 using number_t = big_unsigned_t;
1274 std::vector<int> v;
1275
1276 number_t n = (number_t)e.size();
1277
1278 if (!(r < 1 || n < 1 || (size_t)r > n))
1279 {
1280 v.reserve((size_t)r);
1281
1282 number_t permu = npr((number_t)n - 1, (number_t)r - 1);
1283
1284 while (r) // r != 0
1285 {
1286 // compute index
1287 size_t s = ((size_t)m_th / (size_t)permu);
1288 m_th %= (MType)permu;
1289
1290 // move s-th element of e from e to v
1291 v.emplace_back(e[s]);
1292
1293 // remove s-th element from e
1294 // erase(e, s); --r; --n;
1295 e.erase(e.begin() + s); --r; --n;
1296
1297 if (n > 1) permu /= (number_t)n;
1298 }
1299 }
1300
1301 return v;
1302 }
1303
1304 // this is the fastest and most efficient
1305 template<typename T>
1306 std::vector<T> enum_permutation(T n, T r, T m_th)
1307 {
1308 std::vector<T> v;
1309
1310 if (!(r < 1 || n < 1 || r > n))
1311 {
1312 v.reserve((size_t)r);
1313
1314 std::vector<T> e((size_t)n);
1315
1316 // initialize set e
1317 // e = { 0, 1, 2, ..., n-1}
1318 for (size_t i = 0; i < size_t(n); ++i)
1319 e[i] = T(i);
1320
1321 T permu = npr((T)n - 1, (T)r - 1);
1322
1323 while (r) // r != 0
1324 {
1325 // compute index
1326 size_t s = (size_t)(m_th / permu);
1327 m_th %= permu;
1328
1329 // move s-th element of e from e to v
1330 v.emplace_back(e[s]);
1331
1332 // remove s-th element from e
1333 tpf::types::erase(e, s); --r; --n;
1334
1335 if (n > 1) permu /= (T)n;
1336 }
1337 }
1338
1339 return v;
1340 }
1341
1342 // this is the fastest and most efficient
1343 template<typename T>
1344 std::vector<T> enum_permutation_remainder(T n, T r, T m_th)
1345 {
1346 std::vector<T> v;
1347
1348 if (!(r < 1 || n < 1 || r > n))
1349 {
1350 v.reserve((size_t)r);
1351
1352 std::vector<T> e((size_t)n);
1353
1354 // initialize set e
1355 // e = { 0, 1, 2, ..., n-1}
1356 for (size_t i = 0; i < size_t(n); ++i)
1357 e[i] = T(i);
1358
1359 T permu = npr((T)n - 1, (T)r - 1);
1360
1361 while (r) // r != 0
1362 {
1363 // compute index
1364 size_t s = (size_t)(m_th / permu);
1365 m_th %= permu;
1366
1367 // move s-th element of e from e to v
1368 v.emplace_back(e[s]);
1369
1370 // remove s-th element from e
1371 erase(e, s); --r; --n;
1372
1373 if (n > 1) permu /= (T)n;
1374 }
1375
1376 if(!e.empty())
1377 {
1378 for(auto ele: e) v.emplace_back(ele);
1379 }
1380 }
1381
1382 return v;
1383 }
1384
1385 // this is the fastest and most efficient
1386 template<typename PType, typename NRType, typename MType>
1387 std::vector<NRType> enum_permutation_static(PType permu, NRType n, NRType r, MType m_th)
1388 {
1389 int e[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
1390 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
1391 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
1392 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
1393 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
1394 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
1395 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
1396 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
1397 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
1398 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 };
1399
1400 constexpr size_t ele_count = sizeof(e)/sizeof(size_t) - 1;
1401
1402 int v[ele_count+1]; auto rr = r;
1403
1404 if (!(r < 1 || n < 1 || r > n))
1405 {
1406 while (r) // r != 0
1407 {
1408 // compute index
1409 size_t s = (size_t)(m_th / (MType)permu);
1410 m_th %= (MType)permu;
1411
1412 // move s-th element of e from e to v
1413 v[rr-r] = e[s];
1414
1415 // remove s-th element from e
1416 for(size_t i = s ; i < ele_count; ++i)
1417 e[i] = e[i+1];
1418
1419 --r; --n;
1420
1421 if (n > 1) permu /= (PType)n;
1422 }
1423 }
1424
1425 return { &v[0], &v[rr] };
1426 }
1427
1428 // this is the fastest and most efficient
1429 template<typename T>
1430 std::vector<T> enum_permutation_list(T n, T r, T mth)
1431 {
1432 std::vector<T> v;
1433
1434 if (!(r < 1 || n < 1 || r > n))
1435 {
1436 v.reserve((size_t)r);
1437
1438 std::list<T> e;
1439
1440 // initialize set e
1441 // e = { 0, 1, 2, ..., n-1}
1442 for (size_t i = 0; i < size_t(n); ++i)
1443 e.push_back(i);
1444
1445 T permu = npr((T)n - 1, (T)r - 1);
1446
1447 while (r) // r != 0
1448 {
1449 // compute index
1450 size_t s = size_t(mth / permu);
1451 mth %= permu;
1452
1453 // move s-th element of e from e to v
1454 auto itr = e.begin();
1455 std::advance(itr, s);
1456
1457 v.emplace_back(*itr);
1458
1459 // remove s-th element from e
1460 e.erase(itr); --r; --n;
1461
1462 if (n > 1) permu /= (T)n;
1463 }
1464 }
1465
1466 return v;
1467 }
1468
1469 // returns m_th subset by selecting r elements from
1470 // the set from_set with n elements (from_set.size())
1471 // std::deque<Type> ele should be in order
1472 // ele = { 0, 1, 2, 3 }
1473 template<template<typename, typename...> class ReturnContainer = std::vector,
1474 template<typename, typename...> class SetContainer = std::list, typename... ContainerTails,
1475 typename MthType = unsigned long long, typename EleType = int, typename CountType = int>
1476 ReturnContainer<EleType> enumerate_permutation(MthType m_th,
1477 SetContainer<EleType, ContainerTails...> from_set, CountType r)
1478 {
1479 using number_t = big_unsigned_t;
1480
1481 size_t select_count = (size_t)r;
1482 size_t n = from_set.size();
1483
1484 std::vector<int> v;
1485
1486 if (!(r < 1 || n < 1 || r > n))
1487 {
1488 v.reserve((size_t)r);
1489
1490 std::list<int> e;
1491
1492 // initialize set e, e = { 0, 1, 2, ..., n-1}
1493 for (size_t i = 0; i < n; ++i)
1494 e.push_back(i);
1495
1496 number_t permu = npr((number_t)n - 1, (number_t)r - 1);
1497
1498 while (r) // r != 0
1499 {
1500 // compute index
1501 size_t s = (size_t)(m_th / permu);
1502 m_th %= permu;
1503
1504 // move s-th element of e from e to v
1505 auto itr = e.begin(); std::advance(itr, s);
1506 v.emplace_back(*itr);
1507 // remove s-th element from e
1508 e.erase(itr);
1509 --r; --n;
1510
1511 if (n > 1) permu /= (number_t)n;
1512 }
1513 }
1514
1515 ReturnContainer<EleType> rtn;
1516
1517 if(!v.empty())
1518 {
1519 constexpr auto is_return_vector =
1520 types::is_same_template_v<ReturnContainer<EleType>, std::vector<EleType>>;
1521
1522 if constexpr(is_return_vector)
1523 rtn.reserve(select_count);
1524
1525 for(auto& idx: v)
1526 rtn.emplace_back(from_set[(size_t)idx]);
1527 }
1528
1529 return rtn;
1530 }
1531
1532 } // end of namespace ncrnpr
1533
1544 template<typename CallbackType, typename... ArgTypes>
1546 CallbackType&& callback, ArgTypes&&... args)
1547 {
1548 for(size_t i = range.first;
1549 i < range.second; ++i)
1550 callback(std::forward<ArgTypes>(args)...);
1551 }
1552
1564 template<typename CallbackType, typename... ArgTypes>
1565 void visit_parallel(unsigned int thread_count,
1566 const ncrnpr::range_t& range,
1567 CallbackType&& callback, ArgTypes&&... args)
1568 {
1569 using number_t = big_unsigned_t;
1570 const auto& [start, end] = range.base();
1571
1572 auto ranges =
1574
1575 using future_t = std::future<void>;
1576 using futures_t = std::vector<future_t>;
1577
1578 futures_t futures;
1579 futures.reserve(ranges.size());
1580
1581 auto parallel_func =
1582 visit<tpf::remove_cv_ref_t<CallbackType>,
1584
1585 for(size_t i = 0; i < ranges.size(); ++i)
1586 {
1587 futures.emplace_back(
1588 std::async(std::launch::async,
1589 parallel_func, ranges[i],
1590 std::forward<CallbackType>(callback),
1591 std::forward<ArgTypes>(args)...));
1592 }
1593
1594 for(size_t i = 0; i < ranges.size(); ++i)
1595 {
1596 futures[i].get();
1597 }
1598 }
1599
1610 template<typename CallbackType, typename... ArgTypes>
1612 CallbackType&& callback, ArgTypes&&... args)
1613 {
1614 for(size_t i = range.first;
1615 i < range.second; ++i)
1616 callback(i, std::forward<ArgTypes>(args)...);
1617 }
1618
1630 template<typename CallbackType, typename... ArgTypes>
1632 const ncrnpr::range_t& range,
1633 CallbackType&& callback, ArgTypes&&... args)
1634 {
1635 using number_t = big_unsigned_t;
1636 const auto& [start, end] = range.base();
1637
1638 auto ranges =
1640
1641 using future_t = std::future<void>;
1642 using futures_t = std::vector<future_t>;
1643
1644 futures_t futures;
1645 futures.reserve(ranges.size());
1646
1647 auto parallel_func =
1648 visit_index<tpf::remove_cv_ref_t<CallbackType>,
1650
1651 for(size_t i = 0; i < ranges.size(); ++i)
1652 {
1653 futures.emplace_back(
1654 std::async(std::launch::async,
1655 parallel_func, ranges[i],
1656 std::forward<CallbackType>(callback),
1657 std::forward<ArgTypes>(args)...));
1658 }
1659
1660 for(auto& f: futures) f.get();
1661 }
1662
1675 template<typename NRType, typename CallbackType, typename... ArgTypes>
1676 void visit_permutations(NRType n, NRType r,
1677 const ncrnpr::range_t& range, CallbackType&& callback, ArgTypes&&... args)
1678 {
1679 const auto& [start, end] = range.base();
1680
1681 using number_t = big_unsigned_t;
1682
1683 number_t permu = ncrnpr::npr(n - 1, r - 1);
1684
1685 for(number_t m_th = start; m_th < end; ++m_th)
1686 {
1687 callback(ncrnpr::enum_permutation_static(permu, n, r, m_th),
1688 std::forward<ArgTypes>(args)...);
1689 }
1690 }
1691
1705 template<typename TCType, typename NRType, typename CallbackType, typename... ArgTypes>
1707 NRType n, NRType r,
1708 CallbackType&& callback, ArgTypes&&... args)
1709 {
1710 using number_t = big_unsigned_t;
1711 auto max_m_th = ncrnpr::npr(n, r);
1712
1713 auto ranges =
1714 ncrnpr::split_range_span((size_t)thread_count, 0, max_m_th);
1715
1716 using future_t = std::future<void>;
1717 using futures_t = std::vector<future_t>;
1718
1719 futures_t futures;
1720 futures.reserve(ranges.size());
1721
1722 auto parallel_func = visit_permutations<NRType, tpf::remove_cv_ref_t<CallbackType>,
1724
1725 for(size_t i = 0; i <ranges.size(); ++i)
1726 {
1727 futures.emplace_back(
1728 std::async(std::launch::async,
1729 parallel_func,
1730 n, r, ranges[i],
1731 std::forward<CallbackType>(callback),
1732 std::forward<ArgTypes>(args)...));
1733 }
1734
1735 for(auto& f: futures) f.get();
1736 }
1737
1738 template<typename CallbackType, typename... ArgTypes>
1740 const std::pair<size_t, size_t> permutation_specification,
1741 CallbackType&& callback, ArgTypes&&... args)
1742 {
1743 const auto& [n, r] = permutation_specification;
1744
1745 using number_t = big_unsigned_t;
1746 auto max_m_th = ncrnpr::npr(n, r);
1747 number_t permu = ncrnpr::npr(n - 1, r - 1);
1748
1749 // for clang++ compiler
1750 auto nn = n; auto rr = r;
1751
1752 auto go_parallel = [permu, nn, rr, &callback, &args...](auto m_th)
1753 {
1754 callback(ncrnpr::enum_permutation_static(permu, nn, rr, m_th), args...);
1755 };
1756
1757 #if defined(_GLIBCXX_PARALLEL)
1758
1759 #pragma omp parallel for
1760 for(number_t m_th = 0; m_th < max_m_th; ++m_th)
1761 go_parallel(m_th);
1762
1763 #elif defined(_MSC_VER)
1764
1765 concurrency::parallel_for((number_t)0, max_m_th, go_parallel);
1766
1767 #elif defined(__ICL)
1768
1769 tbb::parallel_for((number_t)0, max_m_th, go_parallel);
1770 #else
1771
1772 #endif
1773
1774
1775 }
1776
1788 template<typename CallbackType, typename... ArgTypes>
1789 void visit_combinations_and_offsets(const std::pair<size_t, size_t>& combination_specification,
1790 const ncrnpr::range_t& range, CallbackType&& callback, ArgTypes&&... args)
1791 {
1792 const auto& [n, r] = combination_specification;
1793 const auto& [start, end] = range.base();
1794
1795 std::vector<int> from_set;
1796 from_set.reserve((size_t)n);
1797
1798 for(size_t i = 0; i < (size_t)n; ++i)
1799 from_set.emplace_back(i);
1800
1801 using number_t = big_unsigned_t;
1802
1803 ncrnpr::combination cmb{n-1, r-1};
1804
1805 for(number_t m_th = start; m_th < end; ++m_th)
1806 {
1807 callback(ncrnpr::enumerate_combination_and_complement(cmb, m_th, from_set, r),
1808 std::forward<ArgTypes>(args)...);
1809 }
1810 }
1811
1812 template<typename NRType, typename CallbackType, typename... ArgTypes>
1813 void visit_combinations(NRType n, NRType r,
1814 const ncrnpr::range_t& range, CallbackType&& callback, ArgTypes&&... args)
1815 {
1816 const auto& [start, end] = range.base();
1817
1818 using number_t = big_unsigned_t;
1819
1820 ncrnpr::combination cmb(n - 1, r - 1);
1821
1822 std::vector<int> from_set;
1823 from_set.reserve((size_t)n);
1824
1825 for(size_t i = 0; i < (size_t)n; ++i)
1826 from_set.emplace_back((int)i);
1827
1828 for(number_t m_th = start; m_th < end; ++m_th)
1829 {
1830 callback(ncrnpr::enumerate_combination_and_complement(cmb, m_th, from_set, r),
1831 std::forward<ArgTypes>(args)...);
1832 }
1833 }
1834
1835 template<typename NRType, typename CallbackType, typename... ArgTypes>
1837 CallbackType&& callback, ArgTypes&&... args)
1838 {
1839 using number_t = big_unsigned_t;
1840 auto max_m_th = ncrnpr::ncr(n, r);
1841
1842 ncrnpr::combination cmb(n - 1, r - 1);
1843
1844 std::vector<int> from_set;
1845 from_set.reserve((size_t)n);
1846
1847 for(size_t i = 0; i < (size_t)n; ++i)
1848 from_set.emplace_back((int)i);
1849
1850 auto go_parallel = [&cmb, &from_set, n, r, &callback, &args...](auto m_th)
1851 {
1852 callback(ncrnpr::enumerate_combination_and_complement(cmb, m_th, from_set, r), args...);
1853 };
1854
1855 #if defined(_GLIBCXX_PARALLEL)
1856
1857 #pragma omp parallel for
1858 for(number_t m_th = 0; m_th < max_m_th; ++m_th)
1859 go_parallel(m_th);
1860
1861 #elif defined(_MSC_VER)
1862 concurrency::parallel_for((number_t)0, max_m_th, go_parallel);
1863
1864 #elif defined(__ICL)
1865 tbb::parallel_for((number_t)0, max_m_th, go_parallel);
1866 #else
1867
1868 #endif
1869 }
1870
1871 template<typename NRType, typename CallbackType, typename... ArgTypes>
1872 void parallel_visit_combinations(NRType n, NRType r,
1873 CallbackType&& callback, ArgTypes&&... args)
1874 {
1875 using number_t = big_unsigned_t;
1876 auto max_m_th = ncrnpr::ncr(n, r);
1877
1878 ncrnpr::combination cmb(n - 1, r - 1);
1879
1880 std::vector<int> from_set;
1881 from_set.reserve((size_t)n);
1882
1883 for(size_t i = 0; i < (size_t)n; ++i)
1884 from_set.emplace_back((int)i);
1885
1886 //from_set.emplace_back((int)0);
1887
1888 auto go_parallel = [&cmb, &from_set, n, r, &callback, &args...](auto m_th)
1889 {
1890 callback(ncrnpr::enumerate_combination(cmb, m_th, from_set, r), args...);
1891 };
1892
1893 #if defined(_GLIBCXX_PARALLEL)
1894
1895 #pragma omp parallel for
1896 for(number_t m_th = 0; m_th < max_m_th; ++m_th)
1897 go_parallel(m_th);
1898
1899 #elif defined(_MSC_VER)
1900 concurrency::parallel_for((number_t)0, max_m_th, go_parallel);
1901
1902 #elif defined(__ICL)
1903 tbb::parallel_for((number_t)0, max_m_th, go_parallel);
1904 #else
1905
1906 #endif
1907 }
1908
1920 template<typename ThreadCountType, typename CallbackType, typename... ArgTypes>
1922 const std::pair<size_t, size_t>& combination_specification,
1923 CallbackType&& callback, ArgTypes&&... args)
1924 {
1925 const auto& [n, r] = combination_specification;
1926
1927 using number_t = big_unsigned_t;
1928 auto max_m_th = ncrnpr::ncr(n, r);
1929
1930 auto ranges =
1932
1933 using future_t = std::future<void>;
1934 using futures_t = std::vector<future_t>;
1935
1936 futures_t futures;
1937 futures.reserve(ranges.size());
1938
1939 auto parallel_func =
1940 visit_combinations_and_offsets<tpf::remove_cv_ref_t<CallbackType>,
1942
1943 for(size_t i = 0; i < ranges.size(); ++i)
1944 {
1945 futures.emplace_back(
1946 std::async(std::launch::async,
1947 parallel_func,
1948 combination_specification, ranges[i],
1949 std::forward<CallbackType>(callback),
1950 std::forward<ArgTypes>(args)...));
1951 }
1952
1953 for(auto& f: futures) f.get();
1954 }
1955
1956} // end of namespace tpf
1957
1958#endif // end of file _TPF_NCRNPR_HPP
std::atomic< int > count
Definition: 022-mutex.cpp:10
void go_parallel(Policy &&policy, IteratorBegin &&begin, IteratorEnd &&end, Callback &&callback)
bool parallel_for(CallbackType &&callback, PolicyType &&policy, BeginType begin_index, EndType end_index)
constexpr auto is_same_v
number_t reset(Type1 n=Type1{}, Type2 r=Type2{})
Definition: tpf_ncrnpr.hpp:580
number_t operator()() const
Definition: tpf_ncrnpr.hpp:576
combination(Type1 n, Type2 r)
Definition: tpf_ncrnpr.hpp:573
combination & operator=(const combination &)=default
friend std::ostream & operator<<(std::ostream &os, const combination &cb)
Definition: tpf_ncrnpr.hpp:708
combination(const combination &)=default
big_unsigned_t number_t
Definition: tpf_ncrnpr.hpp:460
number_t set_n(Type n)
Definition: tpf_ncrnpr.hpp:603
big_integer_t signed_m_th_t
Definition: tpf_ncrnpr.hpp:462
void offset_n(Type offset)
Definition: tpf_ncrnpr.hpp:501
number_t set_r(Type r)
Definition: tpf_ncrnpr.hpp:589
void offset_nr(Type offset)
Definition: tpf_ncrnpr.hpp:470
void offset_r(Type offset)
Definition: tpf_ncrnpr.hpp:532
permutation(const permutation &)=default
friend std::ostream & operator<<(std::ostream &os, const permutation &p)
permutation & operator=(const permutation &)=default
number_t operator()(Type1 n, Type2 r)
permutation(Type1 n, Type2 r)
number_t operator()() const
const base_t & base() const
Definition: tpf_ncrnpr.hpp:105
range_t & operator=(range_t &&)=default
friend std::ostream & operator<<(std::ostream &os, const range_t &range)
Definition: tpf_ncrnpr.hpp:140
range_t(const range_t &)=default
range_t & operator=(const range_t &)=default
std::pair< size_t, size_t > base_t
Definition: tpf_ncrnpr.hpp:97
range_t(range_t &&)=default
std::string str() const
Definition: tpf_ncrnpr.hpp:118
size_t cend() const
Definition: tpf_ncrnpr.hpp:102
range_t(Type1 start, Type2 end)
Definition: tpf_ncrnpr.hpp:114
size_t cbegin() const
Definition: tpf_ncrnpr.hpp:101
std::wstring wstr() const
Definition: tpf_ncrnpr.hpp:129
simple_positive_rational & operator=(const simple_positive_rational &)=default
friend std::ostream & operator<<(std::ostream &os, const simple_positive_rational &r)
Definition: tpf_ncrnpr.hpp:380
simple_positive_rational & operator*=(simple_positive_rational r)
Definition: tpf_ncrnpr.hpp:314
simple_positive_rational(const simple_positive_rational &)=default
simple_positive_rational & operator*=(number_t n)
Definition: tpf_ncrnpr.hpp:299
simple_positive_rational(number_t p, number_t q)
Definition: tpf_ncrnpr.hpp:289
unsigned long long big_unsigned_t
Definition: cpg_types.hpp:223
constexpr size_t InvalidIndex
Definition: cpg_types.hpp:219
long long big_integer_t
Definition: cpg_types.hpp:222
enable_if_in_list_t< Type, integral_list_t, void > reduce(Type &a, Type &b)
Implements nCr, nPr.
Definition: tpf_ncrnpr.hpp:64
int sgn(const ContainerType< EleType, Types... > &cntr)
Computes the inversion of a permutation.
Definition: tpf_ncrnpr.hpp:78
ReturnType enumerate_combination_and_complement(combination cmb, MthType m_th, SetContainer< EleType, ContainerTails... > from_set, SelectCountType select_count)
Definition: tpf_ncrnpr.hpp:792
range_vector_t split_range_count(CountType count, StartType st, EndType ed)
Definition: tpf_ncrnpr.hpp:225
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
auto enumerate_combination_excluding_indices(std::vector< int > exclude_set, SetSizeType set_size, SelectCountType select_count=tpf::InvalidIndex)
std::vector< T > enum_permutation(T n, T r, T m_th)
std::vector< range_t > range_vector_t
Definition: tpf_ncrnpr.hpp:148
ReturnType enumerate_combinations_and_offsets_indices(combination cmb, MthType m_th, std::vector< int > from_set, SelectCountType select_count)
Definition: tpf_ncrnpr.hpp:950
std::vector< NRType > enum_permutation_static(PType permu, NRType n, NRType r, MType m_th)
std::vector< int > enumerate_permutation(std::vector< int > e, RType r, MType m_th)
std::vector< T > enum_permutation_remainder(T n, T r, T m_th)
range_vector_t split_range_span(SpanType min_span, StartType st, EndType ed)
Split range.
Definition: tpf_ncrnpr.hpp:173
auto enumerate_combinations_and_offsets(SetContainer< EleType, ContainerTails... > from_set, SelectCountType select_count=tpf::InvalidIndex)
Definition: tpf_ncrnpr.hpp:899
enable_if_in_list_t< Type, integral_list_t, ReturnType > fact(Type n)
Definition: tpf_ncrnpr.hpp:452
ReturnType enumerate_combination(combination cmb, MthType m_th, SetContainer< EleType, ContainerTails... > from_set, SelectCountType select_count)
Definition: tpf_ncrnpr.hpp:724
auto enumerate_combination_including_indices(std::vector< int > include_set, SetSizeType set_size, SelectCountType select_count=tpf::InvalidIndex)
std::vector< T > enum_permutation_list(T n, T r, T mth)
types::enable_if_integral_t< Type > safe_mul(Type a, Type b)
Safe multiplication of integral types.
ContainerType< EleType > sort(ContainerType< EleType, Types... > container, sort_order order=sort_order::ascending, sort_method method=sort_method::size)
Definition: tpf_set.hpp:438
range< size_t > range_t
std::pair< T, T > range
Type to string name conversions are defined.
Definition: 31-visit.cpp:7
auto erase(ContainerType< EleType, Types... > &container, size_t index)
Definition: tpf_types.hpp:7026
void reverse_order_in_place(ContainerType< Type, Types... > &container)
Definition: tpf_types.hpp:7173
void emplace_back(ContainerType< Type, Types... > &container, EleTypes &&... eles)
Definition: tpf_types.hpp:7150
auto pop_front(ContainerType< Type, Types... > &container)
Definition: tpf_types.hpp:7034
constexpr auto is_same_template_v
Definition: tpf_types.hpp:3399
auto pop_back(ContainerType< Type, Types... > &container)
Definition: tpf_types.hpp:7074
type_list_t< char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long > integral_list_t
Type list of integral type INCLUDING character type, but EXCLUDING boolean type.
Definition: tpf_types.hpp:3198
Includes subnamespace conversion.
Definition: 31-visit.cpp:7
void visit_index(const ncrnpr::range_t &range, CallbackType &&callback, ArgTypes &&... args)
Calls callback(index, args...) in sequence. Iteration index is passed to the callback() function.
void visit_index_parallel(unsigned int thread_count, const ncrnpr::range_t &range, CallbackType &&callback, ArgTypes &&... args)
calls callback(index, args...) in parallel. Iteration index is passed to the callback() as the first ...
constexpr unsigned long long two_power_n(Type n)
Definition: tpf_types.hpp:254
void visit_combinations_and_offsets(const std::pair< size_t, size_t > &combination_specification, const ncrnpr::range_t &range, CallbackType &&callback, ArgTypes &&... args)
Calls callback(enumerated_combination, args...) in sequence enumerated_combination is generated and p...
typename SetTagType::duet_set_t duet_set_t
Definition: tpf_types.hpp:1981
void parallel_visit_combinations_and_complements(NRType n, NRType r, CallbackType &&callback, ArgTypes &&... args)
void visit(const ncrnpr::range_t &range, CallbackType &&callback, ArgTypes &&... args)
Calls callback(args...) function in sequence. Iteration index is not passed to the callback() functio...
void visit_parallel(unsigned int thread_count, const ncrnpr::range_t &range, CallbackType &&callback, ArgTypes &&... args)
Calls callback(args...) function in parallel. Iteration index is not passed to the callback() functio...
void parallel_visit_permutations(const std::pair< size_t, size_t > permutation_specification, CallbackType &&callback, ArgTypes &&... args)
std::remove_cv_t< std::remove_reference_t< Type > > remove_cv_ref_t
Remove const volatile reference from Type.
Definition: tpf_types.hpp:151
typename SetTagType::set_of_duets_t set_of_duets_t
Definition: tpf_types.hpp:1993
void parallel_visit_combinations(NRType n, NRType r, CallbackType &&callback, ArgTypes &&... args)
void visit_permutations_parallel(TCType thread_count, NRType n, NRType r, CallbackType &&callback, ArgTypes &&... args)
Calls callback(enumerated_permutation, args...) in parallel.
void visit_combinations(NRType n, NRType r, const ncrnpr::range_t &range, CallbackType &&callback, ArgTypes &&... args)
void visit_combinations_and_offsets_parallel(ThreadCountType thread_count, const std::pair< size_t, size_t > &combination_specification, CallbackType &&callback, ArgTypes &&... args)
Calls callback(enumerated_combination, args...) in parallel.
void visit_permutations(NRType n, NRType r, const ncrnpr::range_t &range, CallbackType &&callback, ArgTypes &&... args)
Calls callback(enumerated_permutation, args...) in sequence.
std::atomic< int > thread_count
This file implements safe arithmetic.