use num_traits::Num;
use std::{collections::VecDeque, ops::Deref};
pub struct Nibonacci<T> {
memory: VecDeque<T>,
}
impl<T> Nibonacci<T>
where
T: Num + Copy,
{
pub fn new<U>(signature: U) -> Self
where
U: IntoIterator,
U::Item: Deref<Target = T>,
{
let mut nib: Nibonacci<T> = Nibonacci {
memory: VecDeque::new(),
};
for sig_elem in signature {
nib.memory.push_back(*sig_elem);
}
nib
}
}
impl<T> Iterator for Nibonacci<T>
where
T: Num + Copy,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.memory
.push_back(self.memory.iter().fold(T::zero(), |sum, i| sum + *i));
self.memory.pop_front()
}
}
pub fn nibonacci<T, U>(signature: U, n_elem: usize) -> Vec<T>
where
T: Num + Copy,
U: IntoIterator,
U::Item: Deref<Target = T>,
{
Nibonacci::new(signature).take(n_elem).collect()
}
#[cfg(test)]
mod tests {
use crate::nibonacci;
#[test]
fn test_fibonacci() {
assert_eq!(
nibonacci(&[0, 1], 10),
vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
);
}
#[test]
fn test_tribonacci() {
assert_eq!(
nibonacci(&[0., 1., 1.], 10),
vec![0., 1., 1., 2., 4., 7., 13., 24., 44., 81.]
);
assert_eq!(
nibonacci(&[1., 0., 0.], 10),
vec![1., 0., 0., 1., 1., 2., 4., 7., 13., 24.]
);
assert_eq!(
nibonacci(&[0., 0., 0.], 10),
vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]
);
assert_eq!(
nibonacci(&[1., 2., 3.], 10),
vec![1., 2., 3., 6., 11., 20., 37., 68., 125., 230.]
);
assert_eq!(
nibonacci(&[3., 2., 1.], 10),
vec![3., 2., 1., 6., 9., 16., 31., 56., 103., 190.]
);
assert_eq!(nibonacci(&[1., 1., 1.], 1), vec![1.]);
assert_eq!(nibonacci(&[300., 200., 100.], 0), vec![]);
assert_eq!(
nibonacci(&[0.5, 0.5, 0.5], 30),
vec![
0.5, 0.5, 0.5, 1.5, 2.5, 4.5, 8.5, 15.5, 28.5, 52.5, 96.5, 177.5, 326.5, 600.5,
1104.5, 2031.5, 3736.5, 6872.5, 12640.5, 23249.5, 42762.5, 78652.5, 144664.5,
266079.5, 489396.5, 900140.5, 1655616.5, 3045153.5, 5600910.5, 10301680.5
]
);
}
}