Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_mo_algorithm_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
37# include <gtest/gtest.h>
38
39# include <tpl_mo_algorithm.H>
40
41# include <algorithm>
42# include <cstddef>
43# include <random>
44# include <unordered_map>
45# include <unordered_set>
46# include <utility>
47# include <vector>
48
49using namespace Aleph;
50using namespace testing;
51
52namespace
53{
54 // Brute-force: count distinct elements in [l, r]
55 template <typename T>
56 size_t brute_distinct(const std::vector<T> & v, size_t l, size_t r)
57 {
58 std::unordered_set<T> s;
59 for (size_t i = l; i <= r; ++i)
60 s.insert(v[i]);
61 return s.size();
62 }
63
64 // Brute-force: powerful array sum = sum(cnt[x]^2 * x) in [l, r]
65 template <typename T>
66 long long brute_powerful(const std::vector<T> & v, size_t l, size_t r)
67 {
68 std::unordered_map<T, long long> freq;
69 for (size_t i = l; i <= r; ++i)
70 ++freq[v[i]];
71 long long sum = 0;
72 for (auto & [val, cnt] : freq)
73 sum += cnt * cnt * static_cast<long long>(val);
74 return sum;
75 }
76
77 // Brute-force: range mode (max_freq, value) in [l, r]
78 template <typename T>
79 std::pair<size_t, T> brute_mode(const std::vector<T> & v,
80 size_t l, size_t r)
81 {
82 std::unordered_map<T, size_t> freq;
83 for (size_t i = l; i <= r; ++i)
84 ++freq[v[i]];
85 size_t best_f = 0;
86 T best_v = T();
87 for (auto & [val, f] : freq)
88 if (f > best_f)
89 {
90 best_f = f;
91 best_v = val;
92 }
93 return {best_f, best_v};
94 }
95
96 // A trivial sum policy for custom-policy testing
97 struct Sum_Policy
98 {
99 using answer_type = long long;
100
101 long long sum = 0;
102
103 void init(const Array<int> &, size_t) { sum = 0; }
104
105 void add(const Array<int> & data, size_t idx)
106 {
107 sum += data(idx);
108 }
109
110 void remove(const Array<int> & data, size_t idx)
111 {
112 sum -= data(idx);
113 }
114
115 answer_type answer() const { return sum; }
116 };
117} // namespace
118
119// =================================================================
120// Structural / construction tests
121// =================================================================
122
124{
126 EXPECT_EQ(mo.size(), 0u);
127 EXPECT_TRUE(mo.is_empty());
128 auto ans = mo.solve(Array<std::pair<size_t, size_t>>());
129 EXPECT_EQ(ans.size(), 0u);
130}
131
133{
135 EXPECT_EQ(mo.size(), 1u);
136 auto ans = mo.solve({{0, 0}});
137 EXPECT_EQ(ans(0), 1u);
138}
139
141{
142 Distinct_Count_Mo<int> mo = {1, 2, 3};
143
144 // r >= n
145 EXPECT_THROW(mo.solve({{0, 3}}), std::out_of_range);
146
147 // l > r (wrapping size_t isn't possible via pairs, but Mo_Query can)
148 Array<Mo_Query> bad_queries = {{2, 1, 0}};
149 EXPECT_THROW(mo.solve(bad_queries), std::out_of_range);
150}
151
153{
154 // initializer_list
155 Distinct_Count_Mo<int> mo1 = {1, 2, 3};
156 EXPECT_EQ(mo1.size(), 3u);
157
158 // Array<T>
159 Array<int> arr = {1, 2, 3};
161 EXPECT_EQ(mo2.size(), 3u);
162
163 // DynList<T>
164 DynList<int> lst = {1, 2, 3};
166 EXPECT_EQ(mo3.size(), 3u);
167
168 // All should give same answers
169 auto a1 = mo1.solve({{0, 2}});
170 auto a2 = mo2.solve({{0, 2}});
171 auto a3 = mo3.solve({{0, 2}});
172 EXPECT_EQ(a1(0), a2(0));
173 EXPECT_EQ(a2(0), a3(0));
174}
175
177{
178 Distinct_Count_Mo<int> mo1 = {1, 2, 1, 3};
179
180 // Copy
181 auto mo2 = mo1;
182 EXPECT_EQ(mo2.size(), mo1.size());
183 auto a1 = mo1.solve({{0, 3}});
184 auto a2 = mo2.solve({{0, 3}});
185 EXPECT_EQ(a1(0), a2(0));
186
187 // Move
188 auto mo3 = std::move(mo2);
189 auto a3 = mo3.solve({{0, 3}});
190 EXPECT_EQ(a1(0), a3(0));
191
192 // Swap
193 Distinct_Count_Mo<int> mo4 = {10, 20};
194 mo3.swap(mo4);
195 EXPECT_EQ(mo3.size(), 2u);
196 EXPECT_EQ(mo4.size(), 4u);
197}
198
199// =================================================================
200// Distinct count tests
201// =================================================================
202
204{
205 // 0 1 2 3 4 5
206 Distinct_Count_Mo<int> mo = {1, 2, 1, 3, 2, 1};
207 auto ans = mo.solve({{0, 0}, {0, 2}, {1, 4}, {0, 5}, {3, 3}});
208 EXPECT_EQ(ans(0), 1u); // [1] -> {1}
209 EXPECT_EQ(ans(1), 2u); // [1,2,1] -> {1,2}
210 EXPECT_EQ(ans(2), 3u); // [2,1,3,2] -> {1,2,3}
211 EXPECT_EQ(ans(3), 3u); // [1,2,1,3,2,1] -> {1,2,3}
212 EXPECT_EQ(ans(4), 1u); // [3] -> {3}
213}
214
216{
217 Distinct_Count_Mo<int> mo = {5, 5, 5, 5, 5};
218 auto ans = mo.solve({{0, 0}, {0, 4}, {2, 3}});
219 EXPECT_EQ(ans(0), 1u);
220 EXPECT_EQ(ans(1), 1u);
221 EXPECT_EQ(ans(2), 1u);
222}
223
225{
226 Distinct_Count_Mo<int> mo = {10, 20, 30, 40, 50};
227 auto ans = mo.solve({{0, 4}, {1, 3}, {2, 2}});
228 EXPECT_EQ(ans(0), 5u);
229 EXPECT_EQ(ans(1), 3u);
230 EXPECT_EQ(ans(2), 1u);
231}
232
234{
235 const size_t N = 30;
236 std::mt19937 rng(42);
237 std::vector<int> vec(N);
238 for (auto & v : vec)
239 v = rng() % 10;
240
241 auto arr = Array<int>::create(N);
242 for (size_t i = 0; i < N; ++i)
243 arr(i) = vec[i];
244
245 // Generate all O(n^2) queries
247 for (size_t l = 0; l < N; ++l)
248 for (size_t r = l; r < N; ++r)
249 queries.append(std::make_pair(l, r));
250
252 auto ans = mo.solve(queries);
253
254 size_t qi = 0;
255 for (size_t l = 0; l < N; ++l)
256 for (size_t r = l; r < N; ++r)
257 {
259 << "l=" << l << " r=" << r;
260 ++qi;
261 }
262}
263
265{
266 const size_t N = 1000;
267 const size_t Q = 5000;
268 std::mt19937 rng(42);
269
270 std::vector<int> vec(N);
271 for (auto & v : vec)
272 v = rng() % 50;
273
274 auto arr = Array<int>::create(N);
275 for (size_t i = 0; i < N; ++i)
276 arr(i) = vec[i];
277
279 for (size_t i = 0; i < Q; ++i)
280 {
281 size_t a = rng() % N, b = rng() % N;
282 if (a > b) std::swap(a, b);
283 queries.append(std::make_pair(a, b));
284 }
285
287 auto ans = mo.solve(queries);
288
289 for (size_t i = 0; i < Q; ++i)
290 {
291 auto [l, r] = queries(i);
293 << "query " << i << ": l=" << l << " r=" << r;
294 }
295}
296
297// =================================================================
298// Powerful array tests
299// =================================================================
300
302{
303 // 0 1 2 3 4
304 Powerful_Array_Mo<int> mo = {1, 2, 1, 1, 2};
305
306 // [0,0]: {1:1} -> 1^2*1 = 1
307 // [0,2]: {1:2, 2:1} -> 4*1 + 1*2 = 6
308 // [0,4]: {1:3, 2:2} -> 9*1 + 4*2 = 17
309 auto ans = mo.solve({{0, 0}, {0, 2}, {0, 4}});
310 EXPECT_EQ(ans(0), 1LL);
311 EXPECT_EQ(ans(1), 6LL);
312 EXPECT_EQ(ans(2), 17LL);
313}
314
316{
317 const size_t N = 30;
318 std::mt19937 rng(123);
319 std::vector<int> vec(N);
320 for (auto & v : vec)
321 v = rng() % 5 + 1; // positive values
322
323 auto arr = Array<int>::create(N);
324 for (size_t i = 0; i < N; ++i)
325 arr(i) = vec[i];
326
328 for (size_t l = 0; l < N; ++l)
329 for (size_t r = l; r < N; ++r)
330 queries.append(std::make_pair(l, r));
331
333 auto ans = mo.solve(queries);
334
335 size_t qi = 0;
336 for (size_t l = 0; l < N; ++l)
337 for (size_t r = l; r < N; ++r)
338 {
340 << "l=" << l << " r=" << r;
341 ++qi;
342 }
343}
344
346{
347 const size_t N = 500;
348 const size_t Q = 3000;
349 std::mt19937 rng(99);
350
351 std::vector<int> vec(N);
352 for (auto & v : vec)
353 v = rng() % 20 + 1;
354
355 auto arr = Array<int>::create(N);
356 for (size_t i = 0; i < N; ++i)
357 arr(i) = vec[i];
358
360 for (size_t i = 0; i < Q; ++i)
361 {
362 size_t a = rng() % N, b = rng() % N;
363 if (a > b) std::swap(a, b);
364 queries.append(std::make_pair(a, b));
365 }
366
368 auto ans = mo.solve(queries);
369
370 for (size_t i = 0; i < Q; ++i)
371 {
372 auto [l, r] = queries(i);
374 << "query " << i << ": l=" << l << " r=" << r;
375 }
376}
377
378// =================================================================
379// Range mode tests
380// =================================================================
381
383{
384 // 0 1 2 3 4 5
385 Range_Mode_Mo<int> mo = {3, 1, 3, 3, 1, 2};
386
387 auto ans = mo.solve({{0, 5}, {0, 0}, {4, 5}});
388
389 // [0,5]: 3 appears 3 times -> mode freq = 3
390 EXPECT_EQ(ans(0).first, 3u);
391 EXPECT_EQ(ans(0).second, 3);
392
393 // [0,0]: single element 3 -> freq = 1
394 EXPECT_EQ(ans(1).first, 1u);
395
396 // [4,5]: {1,2} -> freq = 1 each
397 EXPECT_EQ(ans(2).first, 1u);
398}
399
401{
402 const size_t N = 30;
403 std::mt19937 rng(77);
404 std::vector<int> vec(N);
405 for (auto & v : vec)
406 v = rng() % 6;
407
408 auto arr = Array<int>::create(N);
409 for (size_t i = 0; i < N; ++i)
410 arr(i) = vec[i];
411
413 for (size_t l = 0; l < N; ++l)
414 for (size_t r = l; r < N; ++r)
415 queries.append(std::make_pair(l, r));
416
418 auto ans = mo.solve(queries);
419
420 size_t qi = 0;
421 for (size_t l = 0; l < N; ++l)
422 for (size_t r = l; r < N; ++r)
423 {
424 auto [bf, bv] = brute_mode(vec, l, r);
425 // Frequency must match; value may differ on ties
426 EXPECT_EQ(ans(qi).first, bf)
427 << "l=" << l << " r=" << r;
428 ++qi;
429 }
430}
431
433{
434 const size_t N = 1000;
435 const size_t Q = 5000;
436 std::mt19937 rng(4242);
437 std::vector<int> vec(N);
438 for (auto & v : vec)
439 v = static_cast<int>(rng() % 200);
440
441 auto arr = Array<int>::create(N);
442 for (size_t i = 0; i < N; ++i)
443 arr(i) = vec[i];
444
446 for (size_t i = 0; i < Q; ++i)
447 {
448 size_t a = rng() % N, b = rng() % N;
449 if (a > b) std::swap(a, b);
450 queries.append(std::make_pair(a, b));
451 }
452
454 auto ans = mo.solve(queries);
455
456 for (size_t i = 0; i < Q; ++i)
457 {
458 auto [l, r] = queries(i);
459 const auto [bf_freq, bf_val] = brute_mode(vec, l, r);
460 (void) bf_val; // Value can differ when there are ties.
461 EXPECT_EQ(ans(i).first, bf_freq)
462 << "query " << i << ": l=" << l << " r=" << r;
463 }
464}
465
466// =================================================================
467// Custom policy test
468// =================================================================
469
471{
472 Gen_Mo_Algorithm<int, Sum_Policy> mo = {3, 1, 4, 1, 5};
473
474 auto ans = mo.solve({{0, 4}, {0, 0}, {2, 3}, {1, 2}});
475 EXPECT_EQ(ans(0), 14LL); // 3+1+4+1+5
476 EXPECT_EQ(ans(1), 3LL); // 3
477 EXPECT_EQ(ans(2), 5LL); // 4+1
478 EXPECT_EQ(ans(3), 5LL); // 1+4
479}
480
481// =================================================================
482// Snake optimization correctness
483// =================================================================
484
486{
487 // Verify that the snake sort doesn't affect final answers
488 // by solving the same queries with a known-correct brute force
489 const size_t N = 50;
490 std::mt19937 rng(2026);
491 std::vector<int> vec(N);
492 for (auto & v : vec)
493 v = rng() % 15;
494
495 auto arr = Array<int>::create(N);
496 for (size_t i = 0; i < N; ++i)
497 arr(i) = vec[i];
498
499 // Generate queries that hit different blocks
501 for (size_t i = 0; i < 200; ++i)
502 {
503 size_t a = rng() % N, b = rng() % N;
504 if (a > b) std::swap(a, b);
505 queries.append(std::make_pair(a, b));
506 }
507
509 auto ans = mo.solve(queries);
510
511 for (size_t i = 0; i < queries.size(); ++i)
512 {
513 auto [l, r] = queries(i);
515 << "query " << i;
516 }
517}
518
519// =================================================================
520// Large stress test
521// =================================================================
522
524{
525 const size_t N = 5000;
526 const size_t Q = 10000;
527 std::mt19937 rng(12345);
528
529 std::vector<int> vec(N);
530 for (auto & v : vec)
531 v = rng() % 100;
532
533 auto arr = Array<int>::create(N);
534 for (size_t i = 0; i < N; ++i)
535 arr(i) = vec[i];
536
538 for (size_t i = 0; i < Q; ++i)
539 {
540 size_t a = rng() % N, b = rng() % N;
541 if (a > b) std::swap(a, b);
542 queries.append(std::make_pair(a, b));
543 }
544
546 auto ans = mo.solve(queries);
547
548 // Verify all queries against brute force
549 for (size_t i = 0; i < Q; ++i)
550 {
551 auto [l, r] = queries(i);
553 << "query " << i;
554 }
555}
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
Offline range query engine using Mo's algorithm.
Array< answer_type > solve(const Array< std::pair< size_t, size_t > > &ranges) const
Solve queries given as (l, r) pairs.
void swap(Gen_Mo_Algorithm &other) noexcept(noexcept(std::swap(std::declval< Policy & >(), std::declval< Policy & >())))
Swap with other in O(1).
#define TEST(name)
static mt19937 rng
#define N
Definition fib.C:294
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
Fw_Itor remove(Fw_Itor __first, const Fw_Itor &__last, const T &__value)
Remove elements equal to a value.
Definition ahAlgo.H:962
static std::atomic< bool > init
Definition hash-fct.C:53
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
double add(double a, double b)
gsl_rng * r
Mo's algorithm for offline range queries.
DynList< int > l