98 cout << " Testing: " << name << "... " << flush; \
104 cout << "\033[32mPASS\033[0m\n"; \
110 cout << "\033[31mFAIL\033[0m (" << msg << ")\n"; \
113# define CHECK(cond, msg) \
115 if (!(cond)) { FAIL(msg); return; } \
118# define CHECK_EQ(a, b, msg) \
122 ss << msg << " (expected " << (b) << ", got " << (a) << ")"; \
128# define CHECK_THROWS(ExType, expr, msg) \
130 bool caught = false; \
131 try { expr; } catch (const ExType &) { caught = true; } \
132 if (!caught) { FAIL(msg); return; } \
137 chrono::high_resolution_clock::time_point
start;
142 auto end = chrono::high_resolution_clock::now();
143 return chrono::duration<double, milli>(end -
start).count();
158 for (
size_t i =
l + 1; i <= r; ++i)
167 for (
size_t i =
l + 1; i <= r; ++i)
176 for (
size_t i =
l + 1; i <= r; ++i)
184 for (
size_t i =
l + 1; i <= r; ++i)
195 constexpr unsigned operator()(
unsigned a,
unsigned b)
const noexcept
211 CHECK(st.is_empty(),
"is_empty");
212 CHECK_EQ(st.num_levels(), 0u,
"levels");
215 "get(0) on empty should throw");
217 "query(0,0) on empty should throw");
224 TEST(
"single element — sum");
236 TEST(
"single element — product");
244 TEST(
"two elements — sum and product");
258 TEST(
"all-equal array (n=100, val=5)");
259 vector<int> v(100, 5);
261 for (
size_t l = 0;
l < 100;
l += 13)
262 for (
size_t r =
l; r < 100; r += 17)
264 "all-equal sum query");
270 TEST(
"sorted ascending — sum");
272 iota(v.begin(), v.end(), 1);
283 TEST(
"sorted descending — product (small)");
295 TEST(
"power-of-two sizes (1, 2, 4, 8, 16, 32, 64)");
296 for (
size_t sz : {1u, 2u, 4u, 8u, 16u, 32u, 64u})
299 for (
size_t i = 0; i < sz; ++i)
300 v[i] =
static_cast<int>(
rng() % 100);
311 TEST(
"non-power-of-two sizes (3, 5, 7, 10, 13, 17, 31, 33, 63, 65, 100)");
312 for (
size_t sz : {3u, 5u, 7u, 10u, 13u, 17u, 31u, 33u, 63u, 65u, 100u})
315 for (
size_t i = 0; i < sz; ++i)
316 v[i] =
static_cast<int>(
rng() % 100);
331 TEST(
"known array sum queries");
350 TEST(
"known array product queries");
352 {2LL, 3LL, 5LL, 7LL, 11LL};
365 TEST(
"get() returns correct element for all positions");
366 vector<int> v = {10, 20, 30, 40, 50};
368 for (
size_t i = 0; i < v.size(); ++i)
375 TEST(
"values() reconstructs original array");
376 vector<int> v = {7, 3, 9, 1, 5, 8, 2};
380 for (
size_t i = 0; i < v.size(); ++i)
391 TEST(
"stress: sum n=200, 5000 random queries");
392 const size_t n = 200;
394 for (
auto & x : v) x =
static_cast<int>(
rng() % 1000) - 500;
397 for (
int q = 0; q < 5000; ++q)
399 size_t l =
rng() % n, r =
rng() % n;
408 TEST(
"stress: product n=50, 3000 random queries (small values)");
411 for (
auto & x : v) x =
static_cast<long long>(
rng() % 5) + 1;
414 for (
int q = 0; q < 3000; ++q)
416 size_t l =
rng() % n, r =
rng() % n;
419 "stress product mismatch");
426 TEST(
"stress: sum n=10000, 50000 random queries");
427 const size_t n = 10000;
429 for (
auto & x : v) x =
static_cast<int>(
rng() % 200) - 100;
432 for (
int q = 0; q < 50000; ++q)
434 size_t l =
rng() % n, r =
rng() % n;
443 TEST(
"stress: all point queries match original (n=500)");
444 const size_t n = 500;
446 for (
auto & x : v) x =
static_cast<int>(
rng() % 10000);
449 for (
size_t i = 0; i < n; ++i)
459 TEST(
"stress: ALL (l,r) pairs for n=80 — exhaustive sum");
462 for (
auto & x : v) x =
static_cast<int>(
rng() % 100) - 50;
465 for (
size_t l = 0;
l < n; ++
l)
466 for (
size_t r =
l; r < n; ++r)
477 TEST(
"XOR disjoint sparse table — known values");
479 {0xA3u, 0x5Fu, 0x12u, 0xB7u, 0x8Cu};
483 CHECK_EQ(st.
query(0, 4), 0xA3u ^ 0x5Fu ^ 0x12u ^ 0xB7u ^ 0x8Cu,
"[0,4]");
491 TEST(
"XOR stress n=300, 10000 queries");
492 const size_t n = 300;
494 for (
auto & x : v) x =
static_cast<unsigned>(
rng());
497 for (
int q = 0; q < 10000; ++q)
499 size_t l =
rng() % n, r =
rng() % n;
508 TEST(
"min via DST cross-validated with Sparse_Table");
509 const size_t n = 200;
511 for (
auto & x : v) x =
static_cast<int>(
rng() % 10000);
516 for (
int q = 0; q < 5000; ++q)
518 size_t l =
rng() % n, r =
rng() % n;
521 "min cross-validation mismatch");
528 TEST(
"max via DST cross-validated with Max_Sparse_Table");
529 const size_t n = 200;
531 for (
auto & x : v) x =
static_cast<int>(
rng() % 10000);
536 for (
int q = 0; q < 5000; ++q)
538 size_t l =
rng() % n, r =
rng() % n;
541 "max cross-validation mismatch");
552 TEST(
"construct from Array<int>");
553 vector<int>
raw = {3, 1, 4, 1, 5, 9, 2, 6};
555 for (
size_t i = 0; i <
raw.
size(); ++i)
564 TEST(
"construct from std::vector<int>");
565 vector<int>
raw = {3, 1, 4, 1, 5, 9, 2, 6};
573 TEST(
"construct from DynList<int>");
574 vector<int>
raw = {3, 1, 4, 1, 5, 9, 2, 6};
576 for (
size_t i = 0; i <
raw.
size(); ++i)
585 TEST(
"construct from initializer_list");
593 TEST(
"construct with uniform init_val (n=50, val=-5)");
603 TEST(
"all constructors produce identical query results");
604 vector<int>
raw = {7, 2, 9, 4, 6, 1, 8, 3, 5};
617 for (
size_t r =
l; r <
raw.
size(); ++r)
633 TEST(
"copy constructor");
634 vector<int> v = {10, 20, 30, 40, 50};
639 for (
size_t l = 0;
l < v.
size(); ++
l)
640 for (
size_t r =
l; r < v.
size(); ++r)
647 TEST(
"move constructor");
648 vector<int> v = {10, 20, 30, 40, 50};
660 TEST(
"copy assignment");
661 vector<int> v1 = {1, 2, 3};
662 vector<int> v2 = {10, 20, 30, 40, 50};
674 TEST(
"move assignment");
675 vector<int> v1 = {1, 2, 3};
676 vector<int> v2 = {10, 20, 30, 40, 50};
712 TEST(
"query throws out_of_range when r >= n");
715 "r=5 >= n=5 should throw");
717 "r=100 should throw");
723 TEST(
"query throws out_of_range when l > r");
726 "l=3 > r=2 should throw");
732 TEST(
"get throws out_of_range when i >= n");
741 TEST(
"boundary queries that should NOT throw");
756 CHECK(
ok,
"boundary queries should not throw");
766 TEST(
"negative values — sum");
775 TEST(
"INT_MAX values — sum (beware overflow)");
778 {1000000000LL, 2000000000LL, 3000000000LL, 4000000000LL};
786 TEST(
"double values — sum");
787 vector<double> v = {1.5, 2.3, -0.8, 4.1, 3.7};
790 double expected = 1.5 + 2.3 + (-0.8) + 4.1 + 3.7;
791 double result = st.
query(0, 4);
798 TEST(
"double values — product");
799 vector<double> v = {0.5, 2.0, 3.0, 0.1, 10.0};
802 double expected = 0.5 * 2.0 * 3.0 * 0.1 * 10.0;
803 double result = st.
query(0, 4);
807 double partial = 2.0 * 3.0 * 0.1;
814 TEST(
"stress: double sum n=500, 5000 queries");
815 const size_t n = 500;
818 for (
auto & x : v) x = dist(
rng);
821 for (
int q = 0; q < 5000; ++q)
823 size_t l =
rng() % n, r =
rng() % n;
826 for (
size_t i =
l; i <= r; ++i)
bf += v[i];
827 double result = st.
query(
l, r);
829 "double stress mismatch");
840 TEST(
"performance: build n=1,000,000");
841 const size_t n = 1000000;
843 for (
auto & x : v) x =
static_cast<int>(
rng() % 1000000);
857 TEST(
"performance: 1,000,000 queries on n=100,000");
858 const size_t n = 100000;
860 for (
auto & x : v) x =
static_cast<int>(
rng() % 1000);
863 volatile long long sink = 0;
865 for (
int q = 0; q < 1000000; ++q)
867 size_t l =
rng() % n, r =
rng() % n;
878 TEST(
"performance: build n=5,000,000");
879 const size_t n = 5000000;
881 for (
auto & x : v) x =
static_cast<int>(
rng() % 1000000);
898 TEST(
"sum is non-idempotent: overlapping would be wrong");
902 vector<int> v = {10, 20, 30, 40, 50};
906 for (
size_t l = 0;
l < v.
size(); ++
l)
907 for (
size_t r =
l; r < v.
size(); ++r)
909 "non-idempotent correctness");
915 TEST(
"num_levels() matches expected formula");
936 vector<int>
v9(9, 1);
948 TEST(
"self copy-assignment (st = st)");
958 for (
size_t i = 0; i < st.
size(); ++i)
965 TEST(
"self swap (st.swap(st))");
977 TEST(
"get(i) == query(i,i) for all i (n=300)");
978 const size_t n = 300;
980 for (
auto & x : v) x =
static_cast<int>(
rng() % 10000) - 5000;
982 for (
size_t i = 0; i < n; ++i)
989 TEST(
"splitting: query(l,r) == op(query(l,m), query(m+1,r))");
992 for (
auto & x : v) x =
static_cast<int>(
rng() % 100) - 50;
995 for (
size_t l = 0;
l < n; ++
l)
996 for (
size_t r =
l + 1; r < n; ++r)
1000 for (
size_t m =
l; m < r; ++m)
1011 TEST(
"splitting: product query(l,r) == query(l,m) * query(m+1,r)");
1012 const size_t n = 30;
1014 for (
auto & x : v) x =
static_cast<long long>(
rng() % 4) + 1;
1017 for (
size_t l = 0;
l < n; ++
l)
1018 for (
size_t r =
l + 1; r < n; ++r)
1021 for (
size_t m =
l; m < r; ++m)
1032 TEST(
"prefix sum: query(0,r) == sum of get(i) for i in [0,r]");
1033 const size_t n = 200;
1035 for (
auto & x : v) x =
static_cast<int>(
rng() % 200) - 100;
1039 for (
size_t r = 0; r < n; ++r)
1049 TEST(
"adversarial: zigzag pattern (alternating high/low)");
1050 const size_t n = 100;
1052 for (
size_t i = 0; i < n; ++i)
1053 v[i] = (i % 2 == 0) ? 1000 : -1000;
1056 for (
size_t l = 0;
l < n; ++
l)
1057 for (
size_t r =
l; r < n; r += 7)
1064 TEST(
"adversarial: single non-zero among zeros");
1065 const size_t n = 128;
1068 vector<int> v(n, 0);
1072 for (
size_t l = 0;
l < n; ++
l)
1073 for (
size_t r =
l; r < n; r += 13)
1084 TEST(
"adversarial: plateau with single spike at every position");
1085 const size_t n = 50;
1088 vector<int> v(n, 1);
1093 static_cast<int>(n - 1) + 1000,
"full range with spike");
1096 static_cast<int>(
spike),
"before spike");
1099 static_cast<int>(n - 1 -
spike),
"after spike");
1106 TEST(
"sliding window queries (width=10) across n=200");
1107 const size_t n = 200;
1108 const size_t w = 10;
1110 for (
auto & x : v) x =
static_cast<int>(
rng() % 1000) - 500;
1113 for (
size_t l = 0;
l +
w - 1 < n; ++
l)
1115 "sliding window mismatch");
1130 TEST(
"string concatenation (non-numeric associative op)");
1131 vector<string> words = {
"the",
" ",
"quick",
" ",
"brown",
" ",
"fox"};
1134 CHECK_EQ(st.
query(0, 6),
string(
"the quick brown fox"),
"[0,6]");
1143 for (
size_t l = 0;
l < words.
size(); ++
l)
1144 for (
size_t r =
l + 1; r < words.
size(); ++r)
1147 for (
size_t m =
l; m < r; ++m)
1158 TEST(
"string concat stress (n=100, all pairs)");
1159 const size_t n = 100;
1161 for (
size_t i = 0; i < n; ++i)
1162 v[i] =
string(1,
'a' +
static_cast<char>(i % 26));
1165 for (
size_t l = 0;
l < n; ++
l)
1166 for (
size_t r =
l; r < n; ++r)
1169 for (
size_t i =
l; i <= r; ++i)
bf += v[i];
1183 seed =
static_cast<unsigned>(
atoi(
argv[1]));
1185 seed =
static_cast<unsigned>(
1186 chrono::system_clock::now().time_since_epoch().count());
1190 cout <<
"╔══════════════════════════════════════════════════════════════╗\n";
1191 cout <<
"║ Disjoint Sparse Table Test Suite ║\n";
1192 cout <<
"║ Testing Gen_Disjoint_Sparse_Table, Sum, Product ║\n";
1193 cout <<
"╚══════════════════════════════════════════════════════════════╝\n";
1194 cout <<
" Seed: " << seed <<
"\n\n";
1196 cout <<
"=== 1. Edge Cases ===\n";
1207 cout <<
"\n=== 2. Basic Correctness ===\n";
1213 cout <<
"\n=== 3. Brute-Force Stress Tests ===\n";
1220 cout <<
"\n=== 4. Custom Operations & Cross-Validation ===\n";
1226 cout <<
"\n=== 5. Construction from All Container Types ===\n";
1234 cout <<
"\n=== 6. Copy, Move, Swap ===\n";
1241 cout <<
"\n=== 7. Exception Safety ===\n";
1247 cout <<
"\n=== 8. Numerical Edge Cases ===\n";
1254 cout <<
"\n=== 9. Performance ===\n";
1259 cout <<
"\n=== 10. Associativity & Disjointness ===\n";
1263 cout <<
"\n=== 11. Robustness & Algebraic Properties ===\n";
1277 cout <<
"\n══════════════════════════════════════════════════════════════\n";
1280 cout <<
" — \033[32mALL PASS\033[0m\n";
1283 cout <<
"══════════════════════════════════════════════════════════════\n";
Simple dynamic array with automatic resizing and functional operations.
T & append(const T &data)
Append a copy of data
Dynamic singly linked list with functional programming support.
T & append(const T &item)
Append a new item by copy.
Disjoint Sparse Table over an arbitrary associative binary operation.
void swap(Gen_Disjoint_Sparse_Table &other) noexcept
Swap this table with other in O(1).
constexpr bool is_empty() const noexcept
True if the table contains no elements.
Array< T > values() const
Reconstruct all original values into an Array.
T get(const size_t i) const
Retrieve the value a[i] in O(1).
constexpr size_t num_levels() const noexcept
Number of precomputed levels.
T query(const size_t l, const size_t r) const
Range query over [l, r] in O(1).
constexpr size_t size() const noexcept
Number of logical elements.
T query(const size_t l, const size_t r) const
Range query over [l, r] in O(1).
size_t size() const noexcept
Count the number of elements of the list.
double elapsed_ms() const
chrono::high_resolution_clock::time_point start
void test_min_cross_validation()
void test_stress_sum_large()
void test_prefix_sum_consistency()
void test_max_cross_validation()
unsigned brute_xor(const vector< unsigned > &v, size_t l, size_t r)
void test_adversarial_single_outlier()
void test_perf_build_large()
void test_adversarial_plateau_with_spike()
void test_string_concatenation()
void test_stress_double_sum()
void test_exception_l_greater_than_r()
void test_single_element_sum()
#define CHECK_EQ(a, b, msg)
void test_construct_from_init_list()
void test_known_sum_array()
void test_exception_r_out_of_range()
void test_construct_all_identical()
void test_string_stress()
void test_stress_product_small()
void test_splitting_composability()
void test_move_constructor()
void test_stress_point_queries()
void test_stress_sum_small()
void test_splitting_product()
void test_exception_get_out_of_range()
void test_boundary_queries_no_throw()
#define CHECK_THROWS(ExType, expr, msg)
void test_construct_from_array()
void test_known_product_array()
T brute_sum(const vector< T > &v, size_t l, size_t r)
void test_move_assignment()
void test_construct_uniform()
void test_power_of_two_sizes()
void test_copy_constructor()
void test_sliding_window()
void test_negative_values()
void test_non_idempotent_correctness()
void test_non_power_of_two_sizes()
void test_construct_from_vector()
void test_copy_assignment()
void test_sorted_ascending()
void test_double_product()
void test_get_equals_point_query()
void test_self_copy_assignment()
void test_values_reconstruct()
T brute_min(const vector< T > &v, size_t l, size_t r)
void test_sorted_descending()
void test_get_all_elements()
T brute_product(const vector< T > &v, size_t l, size_t r)
void test_stress_exhaustive_small()
void test_construct_from_dynlist()
void test_adversarial_zigzag()
void test_single_element_product()
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_max_function > > max(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_abs_function > > abs(const __gmp_expr< T, U > &expr)
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_min_function > > min(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Main namespace for Aleph-w library functions.
T & swap(T &t1, T &t2)
Generic swap using object's swap method.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
std::decay_t< typename HeadC::Item_Type > T
DynList< T > maps(const C &c, Op op)
Classic map operation.
Sparse Table for range maximum queries.
Disjoint Sparse Table for range product queries.
Sparse Table for range minimum queries.
Disjoint Sparse Table for range sum queries.
string operator()(const string &a, const string &b) const
constexpr unsigned operator()(unsigned a, unsigned b) const noexcept
Dynamic array container with automatic resizing.
Disjoint Sparse Table for static range queries in O(1).
Alias for htlist.H (DynList implementation).
Sparse Table for static range queries in O(1).