Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
fenwick_tree.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_fenwick_tree.H>
40
41# include <random>
42# include <vector>
43
44using namespace Aleph;
45using namespace testing;
46
47// ---------------------------------------------------------------
48// Gen_Fenwick_Tree — basic tests (arithmetic defaults)
49// ---------------------------------------------------------------
50
57
59{
61 EXPECT_EQ(ft.size(), 5U);
62 for (size_t i = 0; i < 5; ++i)
63 EXPECT_EQ(ft.get(i), 0);
64}
65
67{
68 Gen_Fenwick_Tree<int> ft = {3, 1, 4, 1, 5, 9};
69
70 // prefix sums: 3, 4, 8, 9, 14, 23
71 EXPECT_EQ(ft.prefix(0), 3);
72 EXPECT_EQ(ft.prefix(1), 4);
73 EXPECT_EQ(ft.prefix(2), 8);
74 EXPECT_EQ(ft.prefix(3), 9);
75 EXPECT_EQ(ft.prefix(4), 14);
76 EXPECT_EQ(ft.prefix(5), 23);
77}
78
80{
81 Array<long> a = {10, 20, 30, 40, 50};
83
84 EXPECT_EQ(ft.prefix(0), 10);
85 EXPECT_EQ(ft.prefix(2), 60);
86 EXPECT_EQ(ft.prefix(4), 150);
87}
88
90{
91 std::vector<int> values = {2, 7, 1, 8, 2, 8};
93
94 EXPECT_EQ(ft.size(), values.size());
95 EXPECT_EQ(ft.get(0), 2);
96 EXPECT_EQ(ft.get(3), 8);
97 EXPECT_EQ(ft.prefix(4), 20); // 2+7+1+8+2
98 EXPECT_EQ(ft.query(1, 4), 18); // 7+1+8+2
99}
100
102{
103 DynList<int> values;
104 values.append(4);
105 values.append(6);
106 values.append(1);
107 values.append(3);
108
110
111 EXPECT_EQ(ft.size(), 4U);
112 EXPECT_EQ(ft.get(2), 1);
113 EXPECT_EQ(ft.prefix(3), 14); // 4+6+1+3
114 EXPECT_EQ(ft.query(1, 3), 10); // 6+1+3
115}
116
118{
120 ft.update(0, 5);
121 ft.update(1, 3);
122 ft.update(2, 7);
123 ft.update(3, 2);
124
125 EXPECT_EQ(ft.get(0), 5);
126 EXPECT_EQ(ft.get(1), 3);
127 EXPECT_EQ(ft.get(2), 7);
128 EXPECT_EQ(ft.get(3), 2);
129
130 EXPECT_EQ(ft.prefix(3), 17);
131}
132
134{
135 Gen_Fenwick_Tree<int> ft = {1, 2, 3, 4, 5, 6, 7, 8};
136
137 EXPECT_EQ(ft.query(0, 7), 36);
138 EXPECT_EQ(ft.query(0, 0), 1);
139 EXPECT_EQ(ft.query(2, 5), 18); // 3+4+5+6
140 EXPECT_EQ(ft.query(3, 3), 4);
141 EXPECT_EQ(ft.query(4, 7), 26); // 5+6+7+8
142}
143
145{
146 Gen_Fenwick_Tree<int> ft = {10, 20, 30};
147
148 ft.set(1, 50);
149
150 EXPECT_EQ(ft.get(0), 10);
151 EXPECT_EQ(ft.get(1), 50);
152 EXPECT_EQ(ft.get(2), 30);
153 EXPECT_EQ(ft.prefix(2), 90);
154}
155
157{
158 Gen_Fenwick_Tree<int> ft = {5, 3, 8, 1};
159 Array<int> vals = ft.values();
160
161 EXPECT_EQ(vals.size(), 4U);
162 EXPECT_EQ(vals(0), 5);
163 EXPECT_EQ(vals(1), 3);
164 EXPECT_EQ(vals(2), 8);
165 EXPECT_EQ(vals(3), 1);
166}
167
169{
170 Gen_Fenwick_Tree<int> ft = {1, 2, 3, 4};
171
172 // copy
174 EXPECT_EQ(ft2.prefix(3), 10);
175
176 // modify copy without affecting original
177 ft2.update(0, 100);
178 EXPECT_EQ(ft.prefix(3), 10);
179 EXPECT_EQ(ft2.prefix(3), 110);
180
181 // move
182 Gen_Fenwick_Tree<int> ft3 = std::move(ft2);
183 EXPECT_EQ(ft3.prefix(3), 110);
184}
185
187{
188 Gen_Fenwick_Tree<int> a = {1, 2, 3};
189 Gen_Fenwick_Tree<int> b = {10, 20};
190
191 a.swap(b);
192
193 EXPECT_EQ(a.size(), 2U);
194 EXPECT_EQ(a.prefix(1), 30);
195 EXPECT_EQ(b.size(), 3U);
196 EXPECT_EQ(b.prefix(2), 6);
197}
198
200{
202 EXPECT_THROW(ft.update(3, 1), std::out_of_range);
203 EXPECT_THROW(ft.prefix(3), std::out_of_range);
204 EXPECT_THROW(ft.query(2, 3), std::out_of_range);
205 EXPECT_THROW(ft.get(5), std::out_of_range);
206 EXPECT_THROW(ft.set(5, 0), std::out_of_range);
207}
208
209// ---------------------------------------------------------------
210// Gen_Fenwick_Tree — XOR group (tests true genericity)
211// ---------------------------------------------------------------
212
213namespace
214{
215 struct Xor_Op
216 {
217 int operator()(int a, int b) const noexcept { return a ^ b; }
218 };
219} // namespace
220
222{
223 // XOR is its own inverse
225
226 ft.update(0, 0b1010);
227 ft.update(1, 0b1100);
228 ft.update(2, 0b0110);
229
230 // prefix XOR: a[0] = 1010, a[0]^a[1] = 0110, a[0]^a[1]^a[2] = 0000
231 EXPECT_EQ(ft.prefix(0), 0b1010);
232 EXPECT_EQ(ft.prefix(1), 0b0110);
233 EXPECT_EQ(ft.prefix(2), 0b0000);
234
235 // range: a[1]^a[2] = 1100 ^ 0110 = 1010
236 EXPECT_EQ(ft.query(1, 2), 0b1010);
237
238 // get recovers original values
239 EXPECT_EQ(ft.get(0), 0b1010);
240 EXPECT_EQ(ft.get(1), 0b1100);
241 EXPECT_EQ(ft.get(2), 0b0110);
242}
243
244// ---------------------------------------------------------------
245// Gen_Fenwick_Tree — stress test against naive prefix sums
246// ---------------------------------------------------------------
247
249{
250 const size_t N = 1000;
251 const int num_ops = 5000;
252
253 std::mt19937 rng(42);
254 std::uniform_int_distribution<size_t> idx_dist(0, N - 1);
255 std::uniform_int_distribution<int> val_dist(-1000, 1000);
256
258 std::vector<long long> naive(N, 0);
259
260 for (int op = 0; op < num_ops; ++op)
261 {
262 size_t i = idx_dist(rng);
263 int delta = val_dist(rng);
264 ft.update(i, delta);
265 naive[i] += delta;
266 }
267
268 // verify all prefix sums
269 long long expected = 0;
270 for (size_t i = 0; i < N; ++i)
271 {
272 expected += naive[i];
273 EXPECT_EQ(ft.prefix(i), expected) << "mismatch at prefix(" << i << ")";
274 }
275
276 // verify individual values
277 for (size_t i = 0; i < N; ++i)
278 EXPECT_EQ(ft.get(i), naive[i]) << "mismatch at get(" << i << ")";
279}
280
281// ---------------------------------------------------------------
282// Fenwick_Tree<T> — arithmetic specialisation
283// ---------------------------------------------------------------
284
286{
287 Fenwick_Tree<int> ft = {5, 3, 8, 1, 7};
288
289 EXPECT_EQ(ft.size(), 5U);
290 EXPECT_EQ(ft.prefix(0), 5);
291 EXPECT_EQ(ft.prefix(4), 24);
292 EXPECT_EQ(ft.query(1, 3), 12); // 3+8+1
293}
294
295// ---------------------------------------------------------------
296// find_kth
297// ---------------------------------------------------------------
298
300{
301 // values: [3, 1, 2, 4]
302 // prefix: [3, 4, 6, 10]
303 Fenwick_Tree<int> ft = {3, 1, 2, 4};
304
305 EXPECT_EQ(ft.find_kth(1), 0U); // prefix(0)=3 >= 1
306 EXPECT_EQ(ft.find_kth(3), 0U); // prefix(0)=3 >= 3
307 EXPECT_EQ(ft.find_kth(4), 1U); // prefix(1)=4 >= 4
308 EXPECT_EQ(ft.find_kth(5), 2U); // prefix(2)=6 >= 5
309 EXPECT_EQ(ft.find_kth(6), 2U); // prefix(2)=6 >= 6
310 EXPECT_EQ(ft.find_kth(7), 3U); // prefix(3)=10 >= 7
311 EXPECT_EQ(ft.find_kth(10), 3U); // prefix(3)=10 >= 10
312 EXPECT_EQ(ft.find_kth(11), 4U); // total=10 < 11, returns size()
313}
314
316{
317 Fenwick_Tree<int> ft = {5};
318
319 EXPECT_EQ(ft.find_kth(1), 0U);
320 EXPECT_EQ(ft.find_kth(5), 0U);
321 EXPECT_EQ(ft.find_kth(6), 1U);
322}
323
325{
326 // Simulate an order-statistic set with values 0..9
327 // Insert values {2, 5, 7} into the frequency array
329 ft.update(2, 1);
330 ft.update(5, 1);
331 ft.update(7, 1);
332
333 // find_kth(1) → 1st smallest = 2
334 EXPECT_EQ(ft.find_kth(1), 2U);
335 // find_kth(2) → 2nd smallest = 5
336 EXPECT_EQ(ft.find_kth(2), 5U);
337 // find_kth(3) → 3rd smallest = 7
338 EXPECT_EQ(ft.find_kth(3), 7U);
339 // find_kth(4) → doesn't exist
340 EXPECT_EQ(ft.find_kth(4), 10U);
341}
342
344{
346 EXPECT_EQ(ft.find_kth(1), 0U);
347}
348
350{
351 // n = 8 (power of two — edge case for bit_floor)
352 Fenwick_Tree<int> ft = {1, 1, 1, 1, 1, 1, 1, 1};
353
354 for (int k = 1; k <= 8; ++k)
355 EXPECT_EQ(ft.find_kth(k), static_cast<size_t>(k - 1));
356
357 EXPECT_EQ(ft.find_kth(9), 8U);
358}
359
361{
362 // values: [0, 0, 5, 0, 3]
363 // prefix: [0, 0, 5, 5, 8]
364 Fenwick_Tree<int> ft = {0, 0, 5, 0, 3};
365
366 EXPECT_EQ(ft.find_kth(1), 2U); // first non-zero prefix at index 2
367 EXPECT_EQ(ft.find_kth(5), 2U);
368 EXPECT_EQ(ft.find_kth(6), 4U);
369 EXPECT_EQ(ft.find_kth(8), 4U);
370}
371
372// ---------------------------------------------------------------
373// Fenwick_Tree — stress find_kth against linear scan
374// ---------------------------------------------------------------
375
377{
378 const size_t N = 512;
379 std::mt19937 rng(123);
380 std::uniform_int_distribution<int> val_dist(0, 10);
381
383 std::vector<int> naive(N, 0);
384
385 for (size_t i = 0; i < N; ++i)
386 {
387 int v = val_dist(rng);
388 ft.update(i, v);
389 naive[i] = v;
390 }
391
392 // build prefix sums for reference
393 std::vector<long long> pfx(N);
394 pfx[0] = naive[0];
395 for (size_t i = 1; i < N; ++i)
396 pfx[i] = pfx[i - 1] + naive[i];
397
398 long long total = pfx[N - 1];
399
400 for (int k = 1; k <= static_cast<int>(total); k += std::max(1, static_cast<int>(total / 200)))
401 {
402 size_t expected = N;
403 for (size_t i = 0; i < N; ++i)
404 if (pfx[i] >= k)
405 {
406 expected = i;
407 break;
408 }
409
410 EXPECT_EQ(ft.find_kth(k), expected)
411 << "find_kth(" << k << ") mismatch";
412 }
413}
414
415// ---------------------------------------------------------------
416// Double type
417// ---------------------------------------------------------------
418
420{
421 Fenwick_Tree<double> ft = {1.5, 2.5, 3.0};
422
423 EXPECT_DOUBLE_EQ(ft.prefix(0), 1.5);
424 EXPECT_DOUBLE_EQ(ft.prefix(1), 4.0);
425 EXPECT_DOUBLE_EQ(ft.prefix(2), 7.0);
426 EXPECT_DOUBLE_EQ(ft.query(1, 2), 5.5);
427}
428
429// ---------------------------------------------------------------
430// Range_Fenwick_Tree — range update + range query
431// ---------------------------------------------------------------
432
439
441{
443 EXPECT_EQ(ft.size(), 5U);
444 for (size_t i = 0; i < 5; ++i)
445 EXPECT_EQ(ft.get(i), 0);
446}
447
449{
450 Range_Fenwick_Tree<int> ft = {3, 1, 4, 1, 5, 9};
451
452 EXPECT_EQ(ft.get(0), 3);
453 EXPECT_EQ(ft.get(1), 1);
454 EXPECT_EQ(ft.get(2), 4);
455 EXPECT_EQ(ft.get(3), 1);
456 EXPECT_EQ(ft.get(4), 5);
457 EXPECT_EQ(ft.get(5), 9);
458
459 EXPECT_EQ(ft.prefix(0), 3);
460 EXPECT_EQ(ft.prefix(2), 8);
461 EXPECT_EQ(ft.prefix(5), 23);
462}
463
465{
466 Array<long> a = {10, 20, 30, 40, 50};
468
469 EXPECT_EQ(ft.prefix(0), 10);
470 EXPECT_EQ(ft.prefix(2), 60);
471 EXPECT_EQ(ft.prefix(4), 150);
472 EXPECT_EQ(ft.query(1, 3), 90); // 20+30+40
473}
474
476{
478
479 ft.update(1, 4, 3); // a[1..4] += 3 → [0, 3, 3, 3, 3, 0]
480
481 EXPECT_EQ(ft.get(0), 0);
482 EXPECT_EQ(ft.get(1), 3);
483 EXPECT_EQ(ft.get(2), 3);
484 EXPECT_EQ(ft.get(3), 3);
485 EXPECT_EQ(ft.get(4), 3);
486 EXPECT_EQ(ft.get(5), 0);
487}
488
490{
492
493 ft.update(1, 4, 3); // [0, 3, 3, 3, 3, 0, 0, 0]
494 ft.update(2, 6, 5); // [0, 3, 8, 8, 8, 5, 5, 0]
495
496 EXPECT_EQ(ft.get(0), 0);
497 EXPECT_EQ(ft.get(1), 3);
498 EXPECT_EQ(ft.get(2), 8);
499 EXPECT_EQ(ft.get(3), 8);
500 EXPECT_EQ(ft.get(4), 8);
501 EXPECT_EQ(ft.get(5), 5);
502 EXPECT_EQ(ft.get(6), 5);
503 EXPECT_EQ(ft.get(7), 0);
504
505 EXPECT_EQ(ft.query(1, 6), 37); // 3+8+8+8+5+5
506}
507
509{
511
512 ft.point_update(0, 5);
513 ft.point_update(1, 3);
514 ft.point_update(2, 7);
515 ft.point_update(3, 2);
516
517 EXPECT_EQ(ft.get(0), 5);
518 EXPECT_EQ(ft.get(1), 3);
519 EXPECT_EQ(ft.get(2), 7);
520 EXPECT_EQ(ft.get(3), 2);
521 EXPECT_EQ(ft.prefix(3), 17);
522}
523
525{
526 Range_Fenwick_Tree<int> ft = {10, 20, 30};
527
528 ft.set(1, 50);
529
530 EXPECT_EQ(ft.get(0), 10);
531 EXPECT_EQ(ft.get(1), 50);
532 EXPECT_EQ(ft.get(2), 30);
533 EXPECT_EQ(ft.prefix(2), 90);
534}
535
537{
538 // Edge case: update touching the last element (r+1 == n)
540
541 ft.update(2, 3, 10); // [0, 0, 10, 10]
542
543 EXPECT_EQ(ft.get(0), 0);
544 EXPECT_EQ(ft.get(1), 0);
545 EXPECT_EQ(ft.get(2), 10);
546 EXPECT_EQ(ft.get(3), 10);
547 EXPECT_EQ(ft.prefix(3), 20);
548}
549
551{
553
554 ft.update(0, 4, 7); // [7, 7, 7, 7, 7]
555
556 for (size_t i = 0; i < 5; ++i)
557 EXPECT_EQ(ft.get(i), 7);
558
559 EXPECT_EQ(ft.prefix(4), 35);
560}
561
563{
564 Range_Fenwick_Tree<int> ft = {5, 3, 8, 1};
565 ft.update(1, 2, 10); // [5, 13, 18, 1]
566
567 Array<int> vals = ft.values();
568 EXPECT_EQ(vals.size(), 4U);
569 EXPECT_EQ(vals(0), 5);
570 EXPECT_EQ(vals(1), 13);
571 EXPECT_EQ(vals(2), 18);
572 EXPECT_EQ(vals(3), 1);
573}
574
576{
577 Range_Fenwick_Tree<int> ft = {1, 2, 3, 4};
578
580 EXPECT_EQ(ft2.prefix(3), 10);
581
582 ft2.update(0, 3, 100);
583 EXPECT_EQ(ft.prefix(3), 10);
584 EXPECT_EQ(ft2.prefix(3), 410);
585
586 Range_Fenwick_Tree<int> ft3 = std::move(ft2);
587 EXPECT_EQ(ft3.prefix(3), 410);
588}
589
591{
592 Range_Fenwick_Tree<int> a = {1, 2, 3};
593 Range_Fenwick_Tree<int> b = {10, 20, 30, 40};
594
595 a.swap(b);
596
597 EXPECT_EQ(a.size(), 4U);
598 EXPECT_EQ(b.size(), 3U);
599
600 // a now contains former b
601 EXPECT_EQ(a.get(0), 10);
602 EXPECT_EQ(a.get(3), 40);
603 EXPECT_EQ(a.prefix(3), 100);
604 EXPECT_EQ(a.query(1, 2), 50);
605
606 // b now contains former a
607 EXPECT_EQ(b.get(0), 1);
608 EXPECT_EQ(b.get(2), 3);
609 EXPECT_EQ(b.prefix(2), 6);
610 EXPECT_EQ(b.query(0, 1), 3);
611}
612
614{
616 EXPECT_THROW(ft.update(0, 3, 1), std::out_of_range);
617 EXPECT_THROW(ft.update(2, 1, 1), std::out_of_range);
618 EXPECT_THROW(ft.prefix(3), std::out_of_range);
619 EXPECT_THROW(ft.query(2, 3), std::out_of_range);
620 EXPECT_THROW(ft.get(5), std::out_of_range);
621}
622
623// ---------------------------------------------------------------
624// Range_Fenwick_Tree — stress test against naive array
625// ---------------------------------------------------------------
626
628{
629 const size_t N = 200;
630 const int num_ops = 2000;
631
632 std::mt19937 rng(77);
633 std::uniform_int_distribution<size_t> idx_dist(0, N - 1);
634 std::uniform_int_distribution<int> val_dist(-100, 100);
635
637 std::vector<long long> naive(N, 0);
638
639 for (int op = 0; op < num_ops; ++op)
640 {
641 size_t a = idx_dist(rng);
642 size_t b = idx_dist(rng);
643 if (a > b)
644 std::swap(a, b);
645 int delta = val_dist(rng);
646
647 ft.update(a, b, delta);
648 for (size_t i = a; i <= b; ++i)
649 naive[i] += delta;
650 }
651
652 // verify all prefix sums
653 long long expected = 0;
654 for (size_t i = 0; i < N; ++i)
655 {
656 expected += naive[i];
657 EXPECT_EQ(ft.prefix(i), expected)
658 << "mismatch at prefix(" << i << ")";
659 }
660
661 // verify individual values
662 for (size_t i = 0; i < N; ++i)
663 EXPECT_EQ(ft.get(i), naive[i])
664 << "mismatch at get(" << i << ")";
665
666 // verify range queries
667 for (int q = 0; q < 500; ++q)
668 {
669 size_t a = idx_dist(rng);
670 size_t b = idx_dist(rng);
671 if (a > b)
672 std::swap(a, b);
673
674 long long naive_sum = 0;
675 for (size_t i = a; i <= b; ++i)
676 naive_sum += naive[i];
677
678 EXPECT_EQ(ft.query(a, b), naive_sum)
679 << "mismatch at query(" << a << ", " << b << ")";
680 }
681}
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
Fenwick tree over an arbitrary abelian group.
void swap(Gen_Fenwick_Tree &other) noexcept
Swap this tree with other in O(1).
T prefix(size_t i) const
Prefix query: Plus(a[0], a[1], ..., a[i]).
constexpr size_t size() const noexcept
Number of logical elements.
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Fenwick tree supporting range updates and range queries.
void swap(Range_Fenwick_Tree &other) noexcept
Swap this tree with other in O(1).
T get(const size_t i) const
Retrieve the logical value a[i].
T prefix(const size_t i) const
Prefix query: sum of a[0..i].
constexpr size_t size() const noexcept
Number of logical elements.
T query(const size_t l, const size_t r) const
Range query: sum of a[l..r].
#define TEST(name)
static mt19937 rng
#define N
Definition fib.C:294
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
Fenwick tree for arithmetic types with find_kth support.
constexpr unsigned operator()(unsigned a, unsigned b) const noexcept
Fenwick tree (Binary Indexed Tree) for prefix queries.