toolbox_rs/
fenwick.rs

1/// Implementation of a Fenwick tree to keep track and rank prefix sums in logarithmic time.
2/// cf. Boris Ryabko (1989). "A fast on-line code" (PDF). Soviet Math. Dokl. 39 (3): 533–537
3///     Peter M. Fenwick (1994). "A new data structure for cumulative frequency tables". Software: Practice and Experience. 24 (3): 327–336
4///
5/// Internally the implementation is one-indexed, while externally it is zero-based. This simplifies the implementation.
6use num::Integer;
7
8#[derive(Clone, Debug)]
9pub struct IndexOutOfRangeError;
10
11#[derive(Clone, Debug)]
12pub struct Fenwick<
13    T: Integer + std::clone::Clone + Copy + std::ops::AddAssign + std::ops::SubAssign,
14> {
15    tree: Vec<T>,
16}
17
18impl<T: Integer + std::clone::Clone + Copy + std::ops::AddAssign + std::ops::SubAssign> Fenwick<T> {
19    /// construct with fixed size.
20    pub fn with_size(n: usize) -> Self {
21        Self {
22            tree: vec![T::zero(); n + 1],
23        }
24    }
25
26    // bulk construction in linear time. Useful for initialization over state trees
27    // Halim, Steven; Halim, Felix; Effendy, Suhendry (3 December 2018). Competitive Programming 4. Vol. 1. Lulu Press
28    pub fn from_values(values: &[T]) -> Self {
29        let mut tree = vec![T::zero()];
30        tree.extend_from_slice(values);
31
32        for index in 1..tree.len() {
33            let parent_index = index + Self::largest_power_of_two_divisor(index);
34            if parent_index < tree.len() {
35                let parent_value = tree[index];
36                tree[parent_index] += parent_value;
37            }
38        }
39        Self { tree }
40    }
41
42    /// retrieves the number of elements in the data structure.
43    pub fn len(&self) -> usize {
44        self.tree.len() - 1
45    }
46
47    pub fn is_empty(&self) -> bool {
48        self.len() == 0
49    }
50
51    /// retrieve the prefix sum at the given zero-based index
52    pub fn rank(&self, index: usize) -> Option<T> {
53        if index >= self.len() {
54            return None;
55        }
56        let mut index = index + 1;
57        let mut sum = T::zero();
58        while index > 0 {
59            sum += self.tree[index];
60            index -= Self::largest_power_of_two_divisor(index);
61        }
62        Some(sum)
63    }
64
65    // update the entry with a new relative value
66    pub fn update(&mut self, index: usize, value: T) -> Result<(), IndexOutOfRangeError> {
67        if index >= self.len() {
68            return Err(IndexOutOfRangeError);
69        }
70        let mut index = index + 1;
71        while index < self.tree.len() {
72            self.tree[index] += value;
73            index += Self::largest_power_of_two_divisor(index);
74        }
75        Ok(())
76    }
77
78    // internal helper function to compute 2 << lsb(n)
79    fn largest_power_of_two_divisor(n: usize) -> usize {
80        // TODO: should this go into math.rs if generally useful?
81        n & n.wrapping_neg()
82    }
83
84    pub fn range(&self, i: usize, j: usize) -> T {
85        if i >= j {
86            return T::zero();
87        }
88
89        let mut sum = T::zero();
90        let mut j = j + 1;
91
92        while j > i {
93            sum += self.tree[j];
94            j -= Self::largest_power_of_two_divisor(j);
95        }
96
97        let mut i = i + 1;
98        while i > j {
99            sum -= self.tree[i];
100            i -= Self::largest_power_of_two_divisor(i);
101        }
102
103        sum
104    }
105
106    /// This function is a straight-forward implementation for range.
107    /// Should be used in testing, or benchmarking mode only.
108    pub fn slow_range(&self, i: usize, j: usize) -> T {
109        if i > j {
110            return T::zero();
111        }
112        self.rank(j).unwrap() - self.rank(i).unwrap()
113    }
114
115    /// finds the index whose prefix sum is less or equal to 'value'
116    /// returns None in the following case:
117    /// value < tree.rank(0), i.e. the prefix sum of the first item is less than the first value
118    pub fn select(&self, mut value: T) -> Option<usize> {
119        let mut index = 0;
120        let mut step = crate::math::prev_power_of_two(self.len());
121        while step > 0 {
122            if index + step < self.tree.len() && self.tree[index + step] <= value {
123                value -= self.tree[index + step];
124                index += step;
125            }
126            step >>= 1;
127        }
128
129        // translate internal 1-based indexing to external 0-based indexing
130        if index == 0 {
131            return None;
132        }
133        Some(index - 1)
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::Fenwick;
140
141    #[test]
142    fn empty_tree() {
143        let fenwick = Fenwick::with_size(0);
144
145        // Test rank on an empty tree
146        assert_eq!(fenwick.rank(0), None);
147
148        // Test select on an empty tree
149        assert_eq!(fenwick.select(0), None);
150
151        // Test range_query on an empty tree
152        assert_eq!(fenwick.range(0, 0), 0);
153    }
154
155    #[test]
156    fn piecemeal_construction1() {
157        let mut fenwick = Fenwick::with_size(30);
158        fenwick.update(0, 10).unwrap();
159        assert_eq!(fenwick.rank(0).unwrap(), 10);
160        assert_eq!(fenwick.rank(1).unwrap(), 10);
161    }
162
163    #[test]
164    fn piecemeal_construction2() {
165        let input = [1, 2, 3, 4];
166        let result = [1, 3, 6, 10];
167        let mut fenwick = Fenwick::with_size(4);
168        for i in 0..input.len() {
169            assert!(fenwick.update(i, input[i]).is_ok());
170        }
171        assert_eq!(fenwick.len(), 4);
172        for i in 0..input.len() {
173            assert_eq!(result[i], fenwick.rank(i).unwrap());
174        }
175    }
176
177    #[test]
178    fn bulk_construction1() {
179        let input = [1, 2, 3, 4];
180        let result = [1, 3, 6, 10];
181        let fenwick = Fenwick::from_values(&input);
182        assert_eq!(fenwick.len(), 4);
183        for i in 0..input.len() {
184            assert_eq!(result[i], fenwick.rank(i).unwrap());
185        }
186    }
187
188    #[test]
189    fn bulk_piecemeal_same() {
190        let input = [19, 3, 27, 28, 263, 3897, -4, 27];
191        let mut fenwick1 = Fenwick::with_size(input.len());
192        for i in 0..input.len() {
193            assert!(fenwick1.update(i, input[i]).is_ok());
194        }
195        let fenwick1 = fenwick1;
196
197        let fenwick2 = Fenwick::from_values(&input);
198
199        assert_eq!(fenwick1.len(), fenwick2.len());
200        for i in 0..input.len() {
201            assert_eq!(fenwick1.rank(i), fenwick2.rank(i));
202        }
203    }
204
205    #[test]
206    fn is_empty() {
207        let fenwick = Fenwick::<u8>::with_size(0);
208        assert!(fenwick.is_empty());
209
210        let fenwick = Fenwick::from_values(&[0, 1, 4]);
211        assert!(!fenwick.is_empty());
212    }
213
214    #[test]
215    fn update_out_of_bounds() {
216        let mut fenwick = Fenwick::from_values(&[0, 1, 4]);
217        assert!(fenwick.update(0, 100).is_ok());
218        assert!(fenwick.update(3, 100).is_err());
219    }
220
221    #[test]
222    fn range_test() {
223        let input = [19, 3, 27, 28, 263, 3897, -4, 27];
224        let fenwick = Fenwick::from_values(&input);
225        for i in 0..input.len() {
226            for j in i..input.len() {
227                assert_eq!(fenwick.slow_range(i, j), fenwick.range(i, j));
228            }
229        }
230    }
231
232    #[test]
233    fn range_i_larger_than_j() {
234        let input = [19, 3, 27, 28, 263, 3897, -4, 27];
235        let fenwick = Fenwick::from_values(&input);
236
237        for i in 0..input.len() {
238            for j in 0..i {
239                assert_eq!(fenwick.slow_range(i, j), fenwick.range(i, j));
240            }
241        }
242    }
243
244    #[test]
245    fn rank() {
246        struct TestCase {
247            value: i32,
248            expected_index: Option<usize>,
249            expected_value: Option<i32>,
250        }
251
252        let input = [19, 3, 27, 28, 263, 3897, 4, 27];
253        // gives prefix sums: [19,22,49,77,340,4237,4241,4268]
254        let fenwick = Fenwick::from_values(&input);
255
256        let test_cases = [
257            TestCase {
258                value: 19,
259                expected_index: Some(0),
260                expected_value: Some(19),
261            },
262            TestCase {
263                value: 18,
264                expected_index: None,
265                expected_value: None,
266            },
267            TestCase {
268                value: 4233,
269                expected_index: Some(4),
270                expected_value: Some(340),
271            },
272            TestCase {
273                value: 4237,
274                expected_index: Some(5),
275                expected_value: Some(4237),
276            },
277            TestCase {
278                value: 4268,
279                expected_index: Some(7),
280                expected_value: Some(4268),
281            },
282            TestCase {
283                value: 5000,
284                expected_index: Some(7),
285                expected_value: Some(4268),
286            },
287        ];
288
289        for test_case in test_cases {
290            let index = fenwick.select(test_case.value);
291            assert_eq!(test_case.expected_index, index);
292            if let Some(index) = index {
293                let value = fenwick.rank(index);
294                assert_eq!(value, test_case.expected_value);
295            } else {
296                assert!(test_case.expected_value.is_none());
297            }
298        }
299
300        // for i in 0..input.len() {
301        //     println!("[{i}] = {}", fenwick.rank(i));
302        // }
303
304        // println!("select(19)={idx}, value: {value}");
305    }
306}