Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-comb.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
38# include <gtest/gtest.h>
39
40# include <ah-comb.H>
41# include <ahFunctional.H>
42
43# include <algorithm>
44# include <array>
45# include <set>
46# include <sstream>
47# include <vector>
48
49using namespace Aleph;
50
51namespace
52{
53std::string list_to_string(const DynList<int> & l)
54{
55 std::ostringstream oss;
56 bool first = true;
57 l.for_each([&](int v)
58 {
59 if (not first)
60 oss << ',';
61 first = false;
62 oss << v;
63 });
64 return oss.str();
65}
66
67template <class Seq>
68std::string seq_to_string(const Seq & s)
69{
70 std::ostringstream oss;
71 for (size_t i = 0; i < s.size(); ++i)
72 {
73 if (i > 0)
74 oss << ',';
75 oss << s(i);
76 }
77 return oss.str();
78}
79
80std::string vector_to_string(const std::vector<int> & v)
81{
82 std::ostringstream oss;
83 for (size_t i = 0; i < v.size(); ++i)
84 {
85 if (i > 0)
86 oss << ',';
87 oss << v[i];
88 }
89 return oss.str();
90}
91}
92
101
103{
104 DynList<int> r1 = {1, 2, 3};
105 DynList<int> r2 = {4, 5, 6};
106 DynList<DynList<int>> m = {r1, r2};
107
108 DynList<int> c1 = {1, 4};
109 DynList<int> c2 = {2, 5};
110 DynList<int> c3 = {3, 6};
112
114
115 auto m2 = m;
118}
119
121{
123
125 r1.reserve(3);
126 r1(0) = 1;
127 r1(1) = 2;
128 r1(2) = 3;
129
130 DynArray<int> r2;
131 r2.reserve(3);
132 r2(0) = 4;
133 r2(1) = 5;
134 r2(2) = 6;
135
136 m.reserve(2);
137 m(0) = r1;
138 m(1) = r2;
139
141
142 ASSERT_EQ(m.size(), 3u);
143 ASSERT_EQ(m(0).size(), 2u);
144 EXPECT_EQ(m(0)(0), 1);
145 EXPECT_EQ(m(0)(1), 4);
146 EXPECT_EQ(m(1)(0), 2);
147 EXPECT_EQ(m(1)(1), 5);
148 EXPECT_EQ(m(2)(0), 3);
149 EXPECT_EQ(m(2)(1), 6);
150}
151
153{
154 DynList<int> l1 = {1, 2};
155 DynList<int> l2 = {10, 20};
157
158 std::set<std::string> perms;
159 bool ok = traverse_perm(l, [&](const DynList<int> & p)
160 {
162 return true;
163 });
164
166 EXPECT_EQ(perms.size(), 4u);
167 EXPECT_TRUE(perms.contains("1,10"));
168 EXPECT_TRUE(perms.contains("2,10"));
169 EXPECT_TRUE(perms.contains("1,20"));
170 EXPECT_TRUE(perms.contains("2,20"));
171}
172
174{
175 DynList<int> l1 = {1, 2, 3};
176 DynList<int> l2 = {10, 20};
178
179 size_t seen = 0;
180 bool ok = traverse_perm(l, [&](const DynList<int> &)
181 {
182 ++seen;
183 return seen < 3; // stop on third call
184 });
185
187 EXPECT_EQ(seen, 3u);
188}
189
191{
192 DynList<int> l1 = {1, 2};
193 DynList<int> l2 = {10};
195
196 auto perms = build_perms(l);
197 EXPECT_EQ(perms.size(), 2u);
198
199 std::set<std::string> s;
200 perms.for_each([&](const DynList<int> & p) { s.insert(list_to_string(p)); });
201 EXPECT_TRUE(s.contains("1,10"));
202 EXPECT_TRUE(s.contains("2,10"));
203}
204
206{
207 DynList<int> l1 = {1, 2};
208 DynList<int> l2 = {2, 1};
210
211 auto combs = build_combs(l);
212
213 // Possible permutations are (1,2), (1,1), (2,2), (2,1).
214 // After sorting: (1,2), (1,1), (2,2), (1,2) => unique: 3
215 EXPECT_EQ(combs.size(), 3u);
216
217 std::set<std::string> s;
218 combs.for_each([&](const DynList<int> & c) { s.insert(list_to_string(c)); });
219 EXPECT_TRUE(s.contains("1,1"));
220 EXPECT_TRUE(s.contains("1,2"));
221 EXPECT_TRUE(s.contains("2,2"));
222}
223
225{
226 DynList<int> l1 = {1, 2};
227 DynList<int> l2 = {10, 20};
229
230 // Sum of first elements across permutations:
231 // (1,10), (2,10), (1,20), (2,20) => sum = 6
232 auto sum = fold_perm<size_t, int>(0u, l, [](size_t a, const DynList<int> & p)
233 {
234 return a + p.get_first();
235 });
236
237 EXPECT_EQ(sum, 6u);
238}
239
241{
243 size_t calls = 0;
244 bool ok = traverse_perm(l, [&](const DynList<int> & p)
245 {
246 ++calls;
248 return true;
249 });
251 EXPECT_EQ(calls, 1u);
252}
253
255{
257 auto perms = build_perms(l);
258 ASSERT_EQ(perms.size(), 1u);
259 EXPECT_TRUE(perms.get_first().is_empty());
260}
261
263{
265 auto combs = build_combs(l);
266 ASSERT_EQ(combs.size(), 1u);
267 EXPECT_TRUE(combs.get_first().is_empty());
268}
269
271{
273 DynList<int> r2;
274 DynList<DynList<int>> m = {r1, r2};
275
276 EXPECT_TRUE(transpose(m).is_empty());
277
278 auto m2 = m;
280 EXPECT_TRUE(m2.is_empty());
281}
282
283#ifndef NDEBUG
285{
286 DynList<int> r1 = {1, 2};
287 DynList<int> r2 = {3};
288 DynList<DynList<int>> m = {r1, r2};
289
290 EXPECT_DEATH((void)transpose(m), "");
291
292 auto m2 = m;
294}
295#endif
296
297// ==== New tests for additional functions ====
298
300{
301 DynList<int> l1 = {1, 2};
302 DynList<int> l2 = {10, 20, 30};
304
305 EXPECT_EQ(perm_count(l), 6u); // 2 * 3
306}
307
309{
311 EXPECT_EQ(perm_count(l), 1u); // One empty permutation
312}
313
315{
316 DynList<int> l1 = {1, 2};
317 DynList<int> l2; // empty
319
320 EXPECT_EQ(perm_count(l), 0u); // Any empty list = 0 permutations
321}
322
324{
325 DynList<int> l1 = {1, 2, 3, 4, 5};
327
328 EXPECT_EQ(perm_count(l), 5u);
329}
330
332{
333 DynList<int> l1 = {1, 2, 3};
334 DynList<int> l2 = {10, 20};
336
337 bool found = exists_perm(l, [](const DynList<int> & p)
338 {
339 return p.get_first() == 2 && p.get_last() == 20;
340 });
341
342 EXPECT_TRUE(found);
343}
344
346{
347 DynList<int> l1 = {1, 2};
348 DynList<int> l2 = {10, 20};
350
351 bool found = exists_perm(l, [](const DynList<int> & p)
352 {
353 return p.get_first() == 100; // Never true
354 });
355
356 EXPECT_FALSE(found);
357}
358
360{
361 DynList<int> l1 = {1, 2, 3};
362 DynList<int> l2 = {10, 20, 30};
364
365 size_t calls = 0;
366 (void)exists_perm(l, [&calls](const DynList<int> & p)
367 {
368 ++calls;
369 return p.get_first() == 1 && p.get_last() == 10; // First one matches
370 });
371
372 EXPECT_EQ(calls, 1u); // Should stop after first match
373}
374
376{
377 DynList<int> l1 = {2, 4};
378 DynList<int> l2 = {10, 20};
380
381 // All sums are >= 12
382 bool all = all_perm(l, [](const DynList<int> & p)
383 {
384 int sum = 0;
385 p.for_each([&sum](int v) { sum += v; });
386 return sum >= 12;
387 });
388
390}
391
393{
394 DynList<int> l1 = {1, 2};
395 DynList<int> l2 = {10, 20};
397
398 bool all = all_perm(l, [](const DynList<int> & p)
399 {
400 return p.get_first() == 2; // Only half satisfy this
401 });
402
404}
405
407{
408 DynList<int> l1 = {1, 2, 3, 4};
409 DynList<int> l2 = {10, 20, 30, 40};
411
412 size_t calls = 0;
413 (void)all_perm(l, [&calls](const DynList<int> & p)
414 {
415 ++calls;
416 return p.get_first() != 1; // First permutation fails
417 });
418
419 EXPECT_EQ(calls, 1u); // Should stop after first failure
420}
421
423{
424 DynList<int> l1 = {1, 2};
425 DynList<int> l2 = {10, 20};
427
428 bool none = none_perm(l, [](const DynList<int> & p)
429 {
430 return p.get_first() == 100; // Never true
431 });
432
434}
435
437{
438 DynList<int> l1 = {1, 2};
439 DynList<int> l2 = {10, 20};
441
442 bool none = none_perm(l, [](const DynList<int> & p)
443 {
444 return p.get_first() == 1; // Some satisfy
445 });
446
448}
449
451{
452 DynList<int> l1 = {1, 2, 3};
453 DynList<int> l2 = {10, 20};
455
456 auto filtered = filter_perm(l, [](const DynList<int> & p)
457 {
458 return p.get_first() >= 2; // Only 2,10 2,20 3,10 3,20
459 });
460
461 EXPECT_EQ(filtered.size(), 4u);
462}
463
465{
466 DynList<int> l1 = {1, 2};
467 DynList<int> l2 = {10, 20};
469
470 auto filtered = filter_perm(l, [](const DynList<int> &)
471 {
472 return false; // None pass
473 });
474
475 EXPECT_TRUE(filtered.is_empty());
476}
477
479{
480 DynList<int> l1 = {1, 2};
481 DynList<int> l2 = {10};
483
484 auto filtered = filter_perm(l, [](const DynList<int> &)
485 {
486 return true; // All pass
487 });
488
489 EXPECT_EQ(filtered.size(), 2u);
490}
491
493{
494 DynList<int> l1 = {1, 2};
495 DynList<int> l2 = {10, 20};
497
498 auto sums = map_perm<int>(l, [](const DynList<int> & p)
499 {
500 int sum = 0;
501 p.for_each([&sum](int v) { sum += v; });
502 return sum;
503 });
504
505 EXPECT_EQ(sums.size(), 4u);
506
507 std::set<int> s;
508 sums.for_each([&s](int v) { s.insert(v); });
509 // (1,10)=11, (2,10)=12, (1,20)=21, (2,20)=22
510 EXPECT_TRUE(s.contains(11));
511 EXPECT_TRUE(s.contains(12));
512 EXPECT_TRUE(s.contains(21));
513 EXPECT_TRUE(s.contains(22));
514}
515
517{
518 DynList<int> l1 = {1, 2};
519 DynList<int> l2 = {10};
521
522 auto strs = map_perm<std::string>(l, [](const DynList<int> & p)
523 {
524 return list_to_string(p);
525 });
526
527 EXPECT_EQ(strs.size(), 2u);
528
529 std::set<std::string> s;
530 strs.for_each([&s](const std::string & v) { s.insert(v); });
531 EXPECT_TRUE(s.contains("1,10"));
532 EXPECT_TRUE(s.contains("2,10"));
533}
534
536{
537 DynList<int> l1 = {1, 2};
538 DynList<int> l2 = {10};
540
541 std::set<std::string> perms;
542 for_each_perm(l, [&perms](const DynList<int> & p)
543 {
545 });
546
547 EXPECT_EQ(perms.size(), 2u);
548 EXPECT_TRUE(perms.contains("1,10"));
549 EXPECT_TRUE(perms.contains("2,10"));
550}
551
553{
555
556 size_t calls = 0;
557 for_each_perm(l, [&calls](const DynList<int> & p)
558 {
560 ++calls;
561 });
562
563 EXPECT_EQ(calls, 1u);
564}
565
567{
568 DynList<int> l1 = {1, 2};
569 DynList<int> l2 = {10, 20};
570 DynList<int> l3 = {100, 200};
572
573 std::set<std::string> perms;
574 traverse_perm(l, [&perms](const DynList<int> & p)
575 {
577 return true;
578 });
579
580 EXPECT_EQ(perms.size(), 8u); // 2 * 2 * 2
581}
582
584{
585 DynList<int> l1 = {42};
587
588 std::set<std::string> perms;
589 traverse_perm(l, [&perms](const DynList<int> & p)
590 {
592 return true;
593 });
594
595 EXPECT_EQ(perms.size(), 1u);
596 EXPECT_TRUE(perms.contains("42"));
597}
598
600{
601 DynList<int> r1 = {1, 2, 3};
603
604 auto t = transpose(m);
605 EXPECT_EQ(t.size(), 3u); // 3 columns => 3 rows
606
607 size_t idx = 1;
608 for (auto it = t.get_it(); it.has_curr(); it.next_ne(), ++idx)
609 {
610 EXPECT_EQ(it.get_curr().size(), 1u);
611 EXPECT_EQ(it.get_curr().get_first(), static_cast<int>(idx));
612 }
613}
614
616{
617 DynList<int> r1 = {1};
618 DynList<int> r2 = {2};
619 DynList<int> r3 = {3};
620 DynList<DynList<int>> m = {r1, r2, r3};
621
622 auto t = transpose(m);
623 EXPECT_EQ(t.size(), 1u); // 1 column => 1 row
624 EXPECT_EQ(t.get_first().size(), 3u); // 3 rows => 3 columns
625
626 DynList<int> expected = {1, 2, 3};
627 EXPECT_EQ(t.get_first(), expected);
628}
629
631{
632 DynList<int> r1 = {1, 2, 3};
634
636 EXPECT_EQ(m.size(), 3u);
637
638 auto it = m.get_it();
639 EXPECT_EQ(it.get_curr().get_first(), 1);
640 it.next_ne();
641 EXPECT_EQ(it.get_curr().get_first(), 2);
642 it.next_ne();
643 EXPECT_EQ(it.get_curr().get_first(), 3);
644}
645
647{
648 DynList<int> r1 = {1, 2};
649 DynList<int> r2 = {3, 4};
650 DynList<DynList<int>> m = {r1, r2};
651
652 auto t = transpose(m);
653
654 DynList<int> c1 = {1, 3};
655 DynList<int> c2 = {2, 4};
657
659}
660
662{
663 DynList<int> l1 = {1};
664 DynList<int> l2 = {1};
666
667 auto combs = build_combs(l);
668 EXPECT_EQ(combs.size(), 1u);
669
670 DynList<int> expected = {1, 1};
671 EXPECT_EQ(sort(combs.get_first()), expected);
672}
673
675{
676 DynList<int> l1 = {1, 2};
677 DynList<int> l2 = {2, 1};
678 DynList<int> l3 = {1, 2};
680
681 auto combs = build_combs(l);
682
683 // Possible combinations after sorting:
684 // (1,1,1), (1,1,2), (1,2,2), (2,2,2)
685 EXPECT_EQ(combs.size(), 4u);
686}
687
689{
690 DynList<int> l1 = {2, 3};
691 DynList<int> l2 = {10};
693
694 // (2,10) and (3,10) => product of first elements = 2 * 3 = 6
695 auto product = fold_perm<int, int>(1, l, [](int acu, const DynList<int> & p)
696 {
697 return acu * p.get_first();
698 });
699
700 EXPECT_EQ(product, 6);
701}
702
704{
705 // 3^5 = 243 permutations
706 DynList<int> l1 = {1, 2, 3};
707 DynList<int> l2 = {10, 20, 30};
708 DynList<int> l3 = {100, 200, 300};
709 DynList<int> l4 = {1000, 2000, 3000};
710 DynList<int> l5 = {10000, 20000, 30000};
711 DynList<DynList<int>> l = {l1, l2, l3, l4, l5};
712
713 EXPECT_EQ(perm_count(l), 243u);
714
715 size_t count = 0;
716 traverse_perm(l, [&count](const DynList<int> & p)
717 {
718 EXPECT_EQ(p.size(), 5u);
719 ++count;
720 return true;
721 });
722
723 EXPECT_EQ(count, 243u);
724}
725
727{
728 DynList<int> l1 = {1, 2};
730
731 // Should not trigger nodiscard warning - use result
732 auto perms = build_perms(l);
733 EXPECT_EQ(perms.size(), 2u);
734}
735
737{
738 DynList<int> l1 = {1, 2};
740
741 // Should not trigger nodiscard warning - use result
742 auto combs = build_combs(l);
743 EXPECT_EQ(combs.size(), 2u);
744}
745
747{
748 DynList<int> r1 = {1, 2};
750
751 // Should not trigger nodiscard warning - use result
752 auto t = transpose(m);
753 EXPECT_EQ(t.size(), 2u);
754}
755
757{
758 DynList<int> l1 = {1, 2};
760
761 // Should not trigger nodiscard warning - use result
762 auto sum = fold_perm<int, int>(0, l, [](int a, const DynList<int> & p)
763 {
764 return a + p.get_first();
765 });
766 EXPECT_EQ(sum, 3);
767}
768
770{
771 DynList<int> l1 = {1, 2};
773
774 // Should not trigger nodiscard warning - use result
775 auto count = perm_count(l);
776 EXPECT_EQ(count, 2u);
777}
778
780{
781 DynList<int> l1 = {1, 2};
783
784 // Should not trigger nodiscard warning - use result
785 auto exists = exists_perm(l, [](const DynList<int> &) { return true; });
787}
788
790{
791 Array<int> a = {1, 2, 3};
792
793 std::vector<std::string> seen;
794 seen.push_back(seq_to_string(a));
795 while (next_permutation(a))
796 seen.push_back(seq_to_string(a));
797
798 const std::vector<std::string> expected = {
799 "1,2,3", "1,3,2", "2,1,3", "2,3,1", "3,1,2", "3,2,1"
800 };
802
803 // Default behavior resets to first permutation at the end.
804 EXPECT_EQ(seq_to_string(a), "1,2,3");
805}
806
808{
809 Array<int> a = {1, 1, 2};
810
811 std::vector<std::string> seen;
812 seen.push_back(seq_to_string(a));
813 while (next_permutation(a))
814 seen.push_back(seq_to_string(a));
815
816 const std::vector<std::string> expected = {
817 "1,1,2", "1,2,1", "2,1,1"
818 };
820 EXPECT_EQ(seq_to_string(a), "1,1,2");
821}
822
824{
825 Array<int> a = {3, 2, 1};
826 std::vector<int> v = {3, 2, 1};
827
828 while (true)
829 {
831
833 const bool hv = std::next_permutation(v.begin(), v.end(),
834 std::greater<int>());
835 EXPECT_EQ(ha, hv);
836
837 if (not ha)
838 break;
839 }
840}
841
848
850{
852 a.reserve(3);
853 a(0) = 1;
854 a(1) = 2;
855 a(2) = 3;
856
857 size_t count = 1;
858 while (next_permutation(a))
859 ++count;
860
861 EXPECT_EQ(count, 6u);
862 EXPECT_EQ(seq_to_string(a), "1,2,3");
863}
864
866{
867 Array<size_t> idx = {0, 1, 2};
868 const size_t n = 5;
869
870 std::vector<std::array<size_t, 3>> seen;
871 while (true)
872 {
873 seen.push_back({idx(0), idx(1), idx(2)});
874 if (not next_combination_indices(idx, n))
875 break;
876 }
877
878 const std::vector<std::array<size_t, 3>> expected = {
879 {0, 1, 2}, {0, 1, 3}, {0, 1, 4}, {0, 2, 3}, {0, 2, 4},
880 {0, 3, 4}, {1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}
881 };
883
884 // Default behavior resets to first combination at the end.
885 EXPECT_EQ(idx(0), 0u);
886 EXPECT_EQ(idx(1), 1u);
887 EXPECT_EQ(idx(2), 2u);
888}
889
891{
892 Array<size_t> idx = {2, 3, 4};
894 EXPECT_EQ(idx(0), 2u);
895 EXPECT_EQ(idx(1), 3u);
896 EXPECT_EQ(idx(2), 4u);
897}
898
900{
901 Array<size_t> not_increasing = {0, 2, 2};
903
904 Array<size_t> out_of_range = {0, 1, 5};
905 EXPECT_THROW(next_combination_indices(out_of_range, 5), std::out_of_range);
906
907 Array<size_t> k_gt_n = {0, 1, 2};
908 EXPECT_THROW(next_combination_indices(k_gt_n, 2), std::domain_error);
909}
910
912{
914 idx.reserve(2);
915 idx(0) = 0;
916 idx(1) = 1;
917
918 size_t count = 1;
919 while (next_combination_indices(idx, 4))
920 ++count;
921
922 EXPECT_EQ(count, 6u); // C(4,2)
923 EXPECT_EQ(idx(0), 0u);
924 EXPECT_EQ(idx(1), 1u);
925}
926
928{
929 EXPECT_EQ(combination_count(0, 0), 1u);
930 EXPECT_EQ(combination_count(5, 0), 1u);
931 EXPECT_EQ(combination_count(5, 5), 1u);
932 EXPECT_EQ(combination_count(5, 2), 10u);
933 EXPECT_EQ(combination_count(5, 3), 10u);
934 EXPECT_EQ(combination_count(20, 10), 184756u);
935 EXPECT_EQ(combination_count(6, 8), 0u);
936}
937
939{
940 if (sizeof(size_t) >= 8)
941 EXPECT_THROW(combination_count(68, 34), std::runtime_error);
942 else
943 EXPECT_THROW(combination_count(35, 17), std::runtime_error);
944}
945
947{
948 uint64_t mask = first_combination_mask(3); // 0b00111
949 const size_t n = 5;
950
951 std::vector<uint64_t> seen;
952 while (true)
953 {
954 seen.push_back(mask);
955 if (not next_combination_mask(mask, n))
956 break;
957 }
958
959 const std::vector<uint64_t> expected = {
960 0x07, 0x0b, 0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c
961 };
963 EXPECT_EQ(mask, uint64_t(0x07)); // reset to first
964}
965
967{
968 uint64_t mask = 0;
969 EXPECT_THROW((void)next_combination_mask(mask, 65), std::out_of_range);
970
971 mask = (uint64_t(1) << 7); // outside n=5
972 EXPECT_THROW((void)next_combination_mask(mask, 5), std::domain_error);
973}
974
976{
977 Array<int> values = {10, 20, 30, 40};
978
979 std::vector<std::string> seen;
980 bool full = for_each_combination(values, 2, [&seen](const Array<int> & c)
981 {
982 seen.push_back(seq_to_string(c));
983 return true;
984 });
985 EXPECT_TRUE(full);
986
987 const std::vector<std::string> expected = {
988 "10,20", "10,30", "10,40", "20,30", "20,40", "30,40"
989 };
991
992 size_t calls = 0;
993 bool done = for_each_combination(values, 3, [&calls](const Array<int> &)
994 {
995 ++calls;
996 return calls < 3;
997 });
999 EXPECT_EQ(calls, 3u);
1000}
1001
1003{
1004 Array<int> values = {1, 2, 3};
1005
1006 size_t calls = 0;
1007 bool ok = for_each_combination(values, 0, [&calls](const Array<int> & c)
1008 {
1009 ++calls;
1010 EXPECT_EQ(c.size(), 0u);
1011 return true;
1012 });
1013 EXPECT_TRUE(ok);
1014 EXPECT_EQ(calls, 1u);
1015
1016 EXPECT_THROW((void)for_each_combination(values, 4,
1017 [](const Array<int> &) { return true; }), std::domain_error);
1018}
1019
1021{
1022 Array<int> values = {1, 2, 3, 4};
1023 auto combs = build_combinations(values, 3);
1024 ASSERT_EQ(combs.size(), 4u);
1025 EXPECT_EQ(seq_to_string(combs(0)), "1,2,3");
1026 EXPECT_EQ(seq_to_string(combs(1)), "1,2,4");
1027 EXPECT_EQ(seq_to_string(combs(2)), "1,3,4");
1028 EXPECT_EQ(seq_to_string(combs(3)), "2,3,4");
1029
1031 dyn.reserve(4);
1032 dyn(0) = 1;
1033 dyn(1) = 2;
1034 dyn(2) = 3;
1035 dyn(3) = 4;
1036
1037 auto combs_dyn = build_combinations(dyn, 2);
1038 ASSERT_EQ(combs_dyn.size(), 6u);
1039 EXPECT_EQ(seq_to_string(combs_dyn(0)), "1,2");
1040 EXPECT_EQ(seq_to_string(combs_dyn(5)), "3,4");
1041}
1042
1044{
1045 DynList<int> l1 = {1, 2};
1047
1048 // Should not trigger nodiscard warning - use result
1049 auto all = all_perm(l, [](const DynList<int> &) { return true; });
1051}
1052
1054{
1055 DynList<int> l1 = {1, 2};
1057
1058 // Should not trigger nodiscard warning - use result
1059 auto none = none_perm(l, [](const DynList<int> &) { return false; });
1061}
1062
1064{
1065 DynList<int> l1 = {1, 2};
1067
1068 // Should not trigger nodiscard warning - use result
1069 auto filtered = filter_perm(l, [](const DynList<int> &) { return true; });
1070 EXPECT_EQ(filtered.size(), 2u);
1071}
1072
1074{
1075 DynList<int> l1 = {1, 2};
1077
1078 // Should not trigger nodiscard warning - use result
1079 auto mapped = map_perm<int>(l, [](const DynList<int> & p) { return p.get_first(); });
1080 EXPECT_EQ(mapped.size(), 2u);
1081}
1082
1084{
1085 // n = 0..7
1086 const std::vector<uint32_t> expected_gray = {
1087 0, 1, 3, 2, 6, 7, 5, 4
1088 };
1089
1090 for (uint32_t i = 0; i < expected_gray.size(); ++i)
1091 {
1092 uint32_t g = bin_to_gray(i);
1093 EXPECT_EQ(g, expected_gray[i]) << "bin_to_gray mismatch at i=" << i;
1094 EXPECT_EQ(gray_to_bin(g), i) << "gray_to_bin mismatch at g=" << g;
1095 }
1096}
1097
1099{
1100 const size_t n = 4;
1101 auto gray = build_gray_code(n);
1102
1103 ASSERT_EQ(gray.size(), 16u);
1104
1105 // Verify adjacency property (exactly one bit difference)
1106 for (size_t i = 1; i < gray.size(); ++i)
1107 {
1108 uint32_t diff = gray[i] ^ gray[i-1];
1109 // diff should be a power of 2
1110 EXPECT_TRUE(diff > 0 && (diff & (diff - 1)) == 0)
1111 << "Not a Gray code sequence at i=" << i
1112 << " (values: " << gray[i-1] << ", " << gray[i] << ")";
1113 }
1114
1115 // Verify cyclic property
1116 uint32_t diff_last = gray[gray.size()-1] ^ gray[0];
1117 EXPECT_TRUE(diff_last > 0 && (diff_last & (diff_last - 1)) == 0);
1118}
1119
1121{
1122 uint64_t val = 0x123456789ABCDEF0ULL;
1123 uint64_t g = bin_to_gray(val);
1124 EXPECT_EQ(gray_to_bin(g), val);
1125}
1126
1128{
1129 EXPECT_THROW(build_gray_code(32), std::domain_error);
1130}
Combinatorics utilities: permutations, combinations and matrix transposition.
Functional programming utilities for Aleph-w containers.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
void reserve(const size_t l, const size_t r)
Allocate a range of entries.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
T & insert(const T &item)
Definition htlist.H:1220
T & get_last() const
Return the last item of the list.
Definition htlist.H:1363
T & get_first() const
Return the first item of the list.
Definition htlist.H:1375
constexpr bool is_empty() const noexcept
Definition htlist.H:419
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:779
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:222
constexpr size_t size() const noexcept
Returns the number of entries in the table.
Definition hashDry.H:619
constexpr bool is_empty() const noexcept
Checks if the table is empty.
Definition hashDry.H:624
#define TEST(name)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool none_perm(const DynList< DynList< T > > &l, Pred &pred)
Check if no permutation satisfies a predicate.
Definition ah-comb.H:721
DynList< DynList< T > > build_combs(const DynList< DynList< T > > &l)
Build the set of unique combinations from a list of lists.
Definition ah-comb.H:558
bool for_each_combination(const Array< T > &values, const size_t k, Op &&op)
Enumerate all k-combinations of an Array<T> in lexicographic index order.
Definition ah-comb.H:1064
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
Array< Array< T > > build_combinations(const Array< T > &values, const size_t k)
Materialize all k-combinations of Array<T>.
Definition ah-comb.H:1088
size_t size(Node *root) noexcept
bool next_combination_indices(Array< size_t > &idx, const size_t n, const bool reset_on_last=true)
Advance an index-combination [i0 < i1 < ... < i(k-1)] to the next one.
Definition ah-comb.H:917
size_t perm_count(const DynList< DynList< T > > &l)
Count the total number of permutations from a list of lists.
Definition ah-comb.H:624
bool traverse_perm(const DynList< DynList< T > > &l, Op &op)
Traverse all the possible permutations that can be done of a list of lists and on each permutation pe...
Definition ah-comb.H:465
constexpr T gray_to_bin(T g) noexcept
Convert a Gray code number to its binary representation.
Definition ah-comb.H:1144
bool next_combination_mask(uint64_t &mask, const size_t n, const bool reset_on_last=true)
Advance a fixed-popcount bitmask to the next combination (Gosper hack).
Definition ah-comb.H:963
DynList< DynList< T > > filter_perm(const DynList< DynList< T > > &l, Pred &pred)
Filter permutations that satisfy a predicate.
Definition ah-comb.H:749
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
bool exists(Container &container, Operation &operation)
Return true if at least one element satisfies a predicate.
DynArray< T > sort(const DynArray< T > &a, Cmp &&cmp=Cmp())
Returns a sorted copy of a DynArray.
Definition ahSort.H:227
Array< uint32_t > build_gray_code(const size_t n)
Generate the sequence of n-bit Gray codes.
Definition ah-comb.H:1164
bool next_permutation(Array< T > &a, Compare cmp=Compare(), const bool reset_on_last=true)
Compute the next lexicographic permutation of an Array.
Definition ah-comb.H:834
void for_each_perm(const DynList< DynList< T > > &l, Op &op)
Apply a procedure to every permutation produced by traverse_perm.
Definition ah-comb.H:505
DynList< DynList< T > > transpose(const DynList< DynList< T > > &l)
Transpose a matrix represented as a list of lists.
Definition ah-comb.H:250
T product(const Container &container, const T &init=T{1})
Compute product of all elements.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
uint64_t first_combination_mask(const size_t k)
Build the first k-of-64 combination mask (k low bits set).
Definition ah-comb.H:934
size_t combination_count(size_t n, size_t k)
Compute n choose k with overflow checks.
Definition ah-comb.H:861
DynList< DynList< T > > build_perms(const DynList< DynList< T > > &l)
Materialize all permutations from a list of lists.
Definition ah-comb.H:537
void in_place_transpose(C< C< T > > &l)
In-place transpose of a rectangular matrix stored as a nested container.
Definition ah-comb.H:301
bool exists_perm(const DynList< DynList< T > > &l, Pred &pred)
Check if any permutation satisfies a predicate.
Definition ah-comb.H:651
constexpr T bin_to_gray(const T n) noexcept
Convert a binary number to its Gray code representation.
Definition ah-comb.H:1126
bool all_perm(const DynList< DynList< T > > &l, Pred &pred)
Check if all permutations satisfy a predicate.
Definition ah-comb.H:691
bool none(const Container &container, Operation &operation)
Return true if no element satisfies operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
DynList< char > l3
DynList< int > l1
DynList< int > l2
DynSetTree< char > l5
DynList< int > l