fenwick_tree/
lib.rs

1//! The crate contains a binary indexed tree ([Fenwick tree](https://en.wikipedia.org/wiki/Fenwick_tree)) implementation and some of the extensions for it.
2//!
3//! The general idea of the Fenwick tree is that it allows for both queries and updates of partial
4//! sums to be performed in _O_(log _n_) time.
5//!
6//! For more details, see [Explanation](#explanation) section.
7//!
8//! For tree API, see [`FenwickTree`] struct.
9//!
10//! # Examples
11//!
12//! Constructing a new tree that is equal to `[1, 2, 3]` array.
13//!
14//! ```
15//! use fenwick_tree::FenwickTree;
16//!
17//! let mut tree = FenwickTree::<i32>::with_len(3);
18//!
19//! // `add` has time complexity O(log n).
20//! tree.add(0, 1).unwrap(); // Adds `1` to element at `0`.
21//! tree.add(1, 2).unwrap(); // Adds `2` to element at `1`.
22//! tree.add(2, 3).unwrap(); // Adds `3` to element at `2`.
23//! ```
24//!
25//! Calculating all possible partial sums of the tree above.
26//!
27//! ```
28//! # use fenwick_tree::FenwickTree;
29//! # let mut tree = FenwickTree::<i32>::with_len(3);
30//! # tree.add(0, 1).unwrap(); // Adds `1` to element at `0`.
31//! # tree.add(1, 2).unwrap(); // Adds `2` to element at `1`.
32//! # tree.add(2, 3).unwrap(); // Adds `3` to element at `2`.
33//! // `sum` has time complexity O(log n).
34//! assert_eq!(tree.sum(0..1).unwrap(), 1);
35//! assert_eq!(tree.sum(0..2).unwrap(), 3);
36//! assert_eq!(tree.sum(0..3).unwrap(), 6);
37//!
38//! assert_eq!(tree.sum(1..2).unwrap(), 2);
39//! assert_eq!(tree.sum(1..3).unwrap(), 5);
40//!
41//! assert_eq!(tree.sum(2..3).unwrap(), 3);
42//! ```
43//!
44//! [`sum`](crate::FenwickTree::sum) accepts [`RangeBounds`](std::ops::RangeBounds), so actually you can use any syntax you'd like.
45//!
46//! ```
47//! # use fenwick_tree::FenwickTree;
48//! # let mut tree = FenwickTree::<i32>::with_len(3);
49//! # tree.add(0, 1).unwrap(); // Adds `1` to element at `0`.
50//! # tree.add(1, 2).unwrap(); // Adds `2` to element at `1`.
51//! # tree.add(2, 3).unwrap(); // Adds `3` to element at `2`.
52//! assert_eq!(tree.sum(..).unwrap(), 6);
53//! assert_eq!(tree.sum(0..).unwrap(), 6);
54//! assert_eq!(tree.sum(..3).unwrap(), 6);
55//! assert_eq!(tree.sum(..=2).unwrap(), 6);
56//! assert_eq!(tree.sum(0..=2).unwrap(), 6);
57//! ```
58//!
59//! For error handling, see [`AddError`] and [`SumError`] structs.
60//!
61//! # Explanation
62//!
63//! In this section, an explanation about the tree implementation is provided.
64//!
65//! ## Indexing
66//!
67//! The easiest explanation considers that indexing of the array is one-based (as in the
68//! [original paper](https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.8917)).
69//!
70//! Sums are stored in the array by the following rule: an item with index `i` stores a cumulative sum
71//! of `[i - g(i), i]` range, where `g(i) = i & (-i)` or the size of the range covered by `i`.
72//!
73//! This looks a bit scary but the whole intuition behind Fenwick tree is very simple:
74//! the position of the first `1` bit in the `i` defines the value of `g(i)`.
75//! * `i = 4 = 100`, `g(i) = 100 (4)` or `[1, 4]` range (note one-based indexing)
76//! * `i = 3 = 011`, `g(i) = 001 (1)` or `[3, 3]` range
77//! * `i = 2 = 010`, `g(i) = 010 (2)` or `[1, 2]` range
78//! * `i = 1 = 001`, `g(i) = 001 (1)` or `[1, 1]` range
79//!
80//! ## Querying
81//!
82//! Prefix sum of `n` items consists of sum of some number of ranges, depending on `n`.
83//! * `n = 4` sum of `[1, 4]` (4 index)
84//! * `n = 3` sum of `[3, 3]` (3 index) and `[1, 2]` (2 index)
85//! * `n = 2` sum of `[1, 2]` (2 index)
86//! * `n = 1` sum of `[1, 1]` (1 index)
87//!
88//! In order to calculate a prefix sum, we need to traverse the array from right
89//! to left, decreasing `i` by `g(i)`.
90//! * `i = 100 (4)`, `i - g(i) = 000 (0)`
91//! * `i = 011 (3)`, `i - g(i) = 010 (2)`
92//! * `i = 010 (2)`, `i - g(i) = 000 (0)`
93//! * `i = 001 (1)`, `i - g(i) = 000 (0)`
94//!
95//! So, how `g(i)` is calculated? This can easily be done by using the
96//! representation of negative numbers in two's complement systems, where `-i` means `!i + 1`.
97//!
98//! ```
99//! # fn any_number() -> i32 { 3 }
100//! let i = any_number();
101//! assert_eq!(!i + 1, -i);
102//! ```
103//!
104//! In binary, `!i` inverts all bits in the `i`, and `!i + 1` flips all bits up to first `0`.
105//! * `i = 001`, `!i = 110`, `-i = 111`
106//! * `i = 010`, `!i = 101`, `-i = 110`
107//! * `i = 011`, `!i = 100`, `-i = 101`
108//! * `i = 100`, `!i = 011`, `-i = 100`
109//!
110//! This means that `i` and `-i` have all bits different except the first `1` bit.
111//! So, `g(i)` is as simple as `i & (-i)`.
112//!
113//! ## Updating
114//!
115//! Updating a value at `i` means traversing the array from left to right, updating
116//! ranges that contain the value.
117//!
118//! Here similar logic applies as for querying: we need to increase `i` by `g(i)`.
119//! * `i = 4 = 100`, `i + g(i) = 1000 (8)`
120//! * `i = 3 = 011`, `i + g(i) = 0100 (4)`
121//! * `i = 2 = 010`, `i + g(i) = 0100 (4)`
122//! * `i = 1 = 001`, `i + g(i) = 0010 (2)`
123//!
124//! That's it!
125//!
126//! ## Notes
127//!
128//! The explanation above assumes one-based indexing, however, in Rust, as in most other programming
129//! languages, indexing is zero-based. Thus, it's not that easy to calculate `i & (-i)` if `i` is
130//! of `usize`.
131//!
132//! For the sake of code simplicity and performance, the following changes were made:
133//! * querying is one-based:  `i & (i - 1)`
134//! * updating is zero-based: `i | (i + 1)`
135//!
136//! # References
137//! * [A New Data Structure for Cumulative Frequency Tables (1994)](https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.8917)
138
139#[cfg(test)]
140mod tests;
141
142mod errors;
143mod tree;
144
145pub use errors::{AddError, SumError};
146pub use tree::FenwickTree;