use crate::ops::{Commutative, Invertible};
use crate::maybe_owned::MaybeOwned;
use std::default::Default;
use std::hash::{Hash, Hasher};
pub struct PrefixPoint<N, O> where O: Commutative<N> {
buf: Vec<N>,
op: O
}
#[inline(always)]
fn lsb(i: usize) -> usize {
i & (1 + !i)
}
#[inline(always)]
unsafe fn combine_mut<N, O: Commutative<N>>(buf: &mut Vec<N>, i: usize, j: usize, op: &O) {
debug_assert!(i != j);
let ptr1 = &mut buf[i] as *mut N;
let ptr2 = &buf[j] as *const N;
op.combine_mut(&mut *ptr1, &*ptr2);
}
#[inline(always)]
unsafe fn uncombine_mut<N, O: Invertible<N>>(buf: &mut Vec<N>, i: usize, j: usize, op: &O) {
debug_assert!(i != j);
let ptr1 = &mut buf[i] as *mut N;
let ptr2 = &buf[j] as *const N;
op.uncombine(&mut *ptr1, &*ptr2);
}
impl<N, O: Commutative<N>> PrefixPoint<N, O> {
pub fn build(mut buf: Vec<N>, op: O) -> PrefixPoint<N, O> {
let len = buf.len();
for i in 0..len {
let j = i + lsb(i+1);
if j < len {
unsafe {
combine_mut::<N, O>(&mut buf, j, i, &op);
}
}
}
PrefixPoint { buf: buf, op: op }
}
pub fn len(&self) -> usize {
self.buf.len()
}
#[inline]
pub fn query(&self, mut i: usize) -> N where N: Clone {
let mut sum = self.buf[i].clone();
i -= lsb(1+i) - 1;
while i > 0 {
sum = self.op.combine_left(sum, &self.buf[i-1]);
i -= lsb(i);
}
sum
}
#[inline]
pub fn query_noclone(&self, mut i: usize) -> MaybeOwned<N> {
let mut sum = MaybeOwned::Borrowed(&self.buf[i]);
i -= lsb(1+i) - 1;
while i > 0 {
sum = MaybeOwned::Owned(match sum {
MaybeOwned::Borrowed(ref v) => self.op.combine(v, &self.buf[i-1]),
MaybeOwned::Owned(v) => self.op.combine_left(v, &self.buf[i-1]),
});
i -= lsb(i);
}
sum
}
#[inline]
pub fn modify(&mut self, mut i: usize, delta: N) {
let len = self.len();
while i < len {
self.op.combine_mut(&mut self.buf[i], &delta);
i += lsb(i+1);
}
}
#[inline(always)]
pub fn truncate(&mut self, size: usize) {
self.buf.truncate(size);
}
#[inline(always)]
pub fn shrink_to_fit(&mut self) {
self.buf.shrink_to_fit();
}
#[inline]
pub fn map<F: FnMut(&mut N)>(&mut self, mut f: F) {
for val in &mut self.buf {
f(val);
}
}
}
impl<N, O: Commutative<N>> Extend<N> for PrefixPoint<N, O> {
fn extend<I: IntoIterator<Item=N>>(&mut self, values: I) {
let oldlen = self.len();
self.buf.extend(values);
let len = self.len();
for i in 0..len {
let j = i + lsb(i+1);
if oldlen <= j && j < len {
unsafe {
combine_mut::<N, O>(&mut self.buf, j, i, &self.op);
}
}
}
}
}
impl<N, O: Commutative<N> + Invertible<N>> PrefixPoint<N, O> {
pub fn get(&self, mut i: usize) -> N where N: Clone {
let mut sum = self.buf[i].clone();
let z = 1 + i - lsb(i+1);
while i != z {
self.op.uncombine(&mut sum, &self.buf[i-1]);
i -= lsb(i);
}
sum
}
pub fn set(&mut self, i: usize, mut value: N) where N: Clone {
let current = self.get(i);
self.op.uncombine(&mut value, ¤t);
self.modify(i, value);
}
pub fn unwrap(self) -> Vec<N> {
let mut buf = self.buf;
let len = buf.len();
for i in (0..len).rev() {
let j = i + lsb(i+1);
if j < len {
unsafe {
uncombine_mut::<N, O>(&mut buf, j, i, &self.op);
}
}
}
buf
}
pub fn unwrap_clone(&self) -> Vec<N> where N: Clone {
let len = self.buf.len();
let mut buf = self.buf.clone();
for i in (0..len).rev() {
let j = i + lsb(i+1);
if j < len {
unsafe {
uncombine_mut::<N, O>(&mut buf, j, i, &self.op);
}
}
}
buf
}
}
impl<N: Clone, O: Commutative<N> + Clone> Clone for PrefixPoint<N, O> {
fn clone(&self) -> PrefixPoint<N, O> {
PrefixPoint {
buf: self.buf.clone(), op: self.op.clone()
}
}
}
impl<N, O: Commutative<N> + Default> Default for PrefixPoint<N, O> {
#[inline]
fn default() -> PrefixPoint<N, O> {
PrefixPoint { buf: Vec::new(), op: Default::default() }
}
}
impl<'a, N: 'a + Hash, O: Commutative<N>> Hash for PrefixPoint<N, O> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.buf.hash(state);
}
}
#[cfg(test)]
mod tests {
pub fn compute_prefix_sum<N: ::std::ops::Add<Output=N> + Copy>(buf: &mut[N]) {
let mut iter = buf.iter_mut();
match iter.next() {
None => {},
Some(s) => {
let mut sum = *s;
for item in iter {
sum = sum + *item;
*item = sum;
}
}
}
}
use super::*;
use rand::distributions::Standard;
use rand::prelude::*;
use std::num::Wrapping;
use crate::ops::Add;
fn random_vec(rng: &mut ThreadRng, len: usize) -> Vec<Wrapping<i32>> {
rng.sample_iter(&Standard).map(|i| Wrapping(i)).take(len).collect()
}
#[test]
fn fenwick_query() {
let mut rng = thread_rng();
for n in 0..130 {
let mut vec = random_vec(&mut rng, n);
let fenwick = PrefixPoint::build(vec.clone(), Add);
compute_prefix_sum(&mut vec);
for i in 0..vec.len() {
assert_eq!(vec[i], fenwick.query(i));
assert_eq!(&vec[i], fenwick.query_noclone(i).borrow());
}
}
}
#[test]
fn fenwick_map() {
let mut rng = thread_rng();
for n in 0..130 {
let mut vec = random_vec(&mut rng, n);
let mut fenwick = PrefixPoint::build(vec.clone(), Add);
assert_eq!(fenwick.clone().unwrap(), vec);
assert_eq!(fenwick.clone().unwrap_clone(), vec);
compute_prefix_sum(&mut vec);
fenwick.map(|n| *n = Wrapping(12) * *n);
for i in 0..vec.len() {
assert_eq!(vec[i]*Wrapping(12), fenwick.query(i));
}
}
}
#[test]
fn fenwick_modify() {
let mut rng = thread_rng();
for n in 0..130 {
let mut vec = random_vec(&mut rng, n);
let diff = random_vec(&mut rng, n);
let mut fenwick = PrefixPoint::build(vec.clone(), Add);
for i in 0..diff.len() {
let mut ps: Vec<Wrapping<i32>> = vec.clone();
compute_prefix_sum(&mut ps);
assert_eq!(fenwick.clone().unwrap(), vec);
assert_eq!(fenwick.clone().unwrap_clone(), vec);
for j in 0..vec.len() {
assert_eq!(ps[j], fenwick.query(j));
assert_eq!(vec[j], fenwick.get(j));
}
vec[i] += diff[i];
fenwick.modify(i, diff[i]);
}
}
}
#[test]
fn fenwick_set() {
let mut rng = thread_rng();
for n in 0..130 {
let mut vec = random_vec(&mut rng, n);
let diff = random_vec(&mut rng, n);
let mut fenwick = PrefixPoint::build(vec.clone(), Add);
for i in 0..diff.len() {
let mut ps: Vec<Wrapping<i32>> = vec.clone();
compute_prefix_sum(&mut ps);
assert_eq!(fenwick.clone().unwrap(), vec);
assert_eq!(fenwick.clone().unwrap_clone(), vec);
for j in 0..vec.len() {
assert_eq!(ps[j], fenwick.query(j));
assert_eq!(vec[j], fenwick.get(j));
}
vec[i] = diff[i];
fenwick.set(i, diff[i]);
}
}
}
#[test]
fn fenwick_extend() {
let mut rng = thread_rng();
for n in 0..130 {
let vec = random_vec(&mut rng, n);
let mut sum = vec.clone();
compute_prefix_sum(&mut sum);
for i in 0..sum.len() {
let mut fenwick = PrefixPoint::build(vec.iter().take(i/2).map(|&i| i).collect(), Add);
fenwick.extend(vec.iter().skip(i/2).take(i - i/2).map(|&i| i));
for j in 0..i {
assert_eq!(sum[j], fenwick.query(j));
}
}
}
}
}