1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Operations on a 1D Fenwick tree stored in a zero-based slice.
//!
//! # Examples
//!
//! ```
//! use fenwick::array::{update, prefix_sum};
//!
//! let fw = &mut [0i32; 10]; // backing array of Fenwick tree (NOT original array!)
//! assert_eq!(prefix_sum(fw, 0), 0);
//! assert_eq!(prefix_sum(fw, 9), 0);
//! update(fw, 0, 3); // original array: [3, 0, 0, 0, 0, 0, 0, 0, 0, 0]
//! assert_eq!(prefix_sum(fw, 0), 3);
//! assert_eq!(prefix_sum(fw, 9), 3);
//! update(fw, 5, 9); // original array: [3, 0, 0, 0, 0, 9, 0, 0, 0, 0]
//! assert_eq!(prefix_sum(fw, 4), 3);
//! assert_eq!(prefix_sum(fw, 5), 12);
//! assert_eq!(prefix_sum(fw, 6), 12);
//! update(fw, 4, -5); // original array: [3, 0, 0, 0, -5, 9, 0, 0, 0, 0]
//! assert_eq!(prefix_sum(fw, 4), -2);
//! assert_eq!(prefix_sum(fw, 5), 7);
//! update(fw, 0, -2); // original array: [1, 0, 0, 0, -5, 9, 0, 0, 0, 0]
//! assert_eq!(prefix_sum(fw, 4), -4);
//! assert_eq!(prefix_sum(fw, 5), 5);
//! ```
//!

// NOTE: example above used in `README`

use std::ops::AddAssign;

use index::zero_based::{down as seq_dn, up as seq_up};

/// Updates one element in the Fenwick tree stored in a borrowed slice (zero-based).
///
/// Conceptually performs `a[i] += delta` on the original array `a`.
///
/// # Panics
///
/// Panics if `fenwick[i]` is out of bound.
///
/// # Examples
///
/// See [module-level example](self).
///
pub fn update<T>(fenwick: &mut [T], i: usize, delta: T)
where
    T: AddAssign + Copy + Default
{
    for ii in seq_up(i, fenwick.len()) {
        fenwick[ii] += delta;
    }
}

/// Calculates the prefix sum up to and including `i` in the Fenwick tree stored in a borrowed slice
/// (zero-based).
///
/// Conceptually calculates `a[0] + ... + a[i]` on the original array `a`.
///
/// # Panics
///
/// Panics if `fenwick[i]` is out of bound.
///
/// # Examples
///
/// See [module-level example](self).
///
pub fn prefix_sum<T>(fenwick: &[T], i: usize) -> T
where
    T: AddAssign + Copy + Default
{
    let mut sum = T::default();
    for ii in seq_dn(i) {
        sum += fenwick[ii];
    }
    sum
}

#[cfg(test)]
mod tests {
    use std::ops::AddAssign;
    use rand::{thread_rng, Rng, distributions::{Distribution, Range}};

    fn partial_sum_scanner<T>(s: &mut T, x: &T) -> Option<T>
    where
        T: AddAssign + Copy,
    {
        *s += *x;
        Some(*s)
    }

    #[test]
    fn randoms() {
        let mut rng = thread_rng();
        for len in 0..130usize {
            random_one(&mut rng, len);
        }
    }
    fn random_one<TRng: Rng>(rng: &mut TRng, len: usize) {
        let mut data = vec![0i32; len];
        let range = Range::new_inclusive(-50, 50);
        for x in data.iter_mut() {
            *x = range.sample(rng);
        }
        let psum: Vec<i32> = data.iter().scan(0i32, partial_sum_scanner).collect();
        let mut fenwick = vec![0i32; data.len()];
        {
            for (i, x) in data.iter().enumerate() {
                super::update(&mut fenwick, i, *x);
            }
        }
        for (i, s) in psum.iter().enumerate() {
            assert_eq!(super::prefix_sum(&fenwick, i), *s);
        }
    }
}