use std::ops::{AddAssign, Mul, SubAssign};
pub fn convolve<T>(a: &[T], b: &[T]) -> Vec<T>
where
T: AddAssign + SubAssign + Mul<Output = T> + Default + Clone,
{
let n = a.len();
let m = b.len();
let nm = n.max(m);
let mut a = a.to_vec();
a.resize_with(nm, T::default);
let mut b = b.to_vec();
b.resize_with(nm, T::default);
let mut ab = mul(&mut a, &mut b);
ab.truncate(n + m - 1);
ab
}
const NAIVE_THRESHOLD: usize = 32;
fn mul<T>(a: &mut [T], b: &mut [T]) -> Vec<T>
where
T: AddAssign + SubAssign + Mul<Output = T> + Default + Clone,
{
assert_eq!(a.len(), b.len());
let n = a.len();
if n <= NAIVE_THRESHOLD {
let mut res = vec![T::default(); n + n - 1];
for (i, ai) in a.iter().enumerate() {
for (j, bj) in b.iter().enumerate() {
res[i + j] += ai.clone() * bj.clone();
}
}
return res;
}
let nl = n / 2;
let nh = n - nl;
let (al, ah) = a.split_at_mut(nl);
let (bl, bh) = b.split_at_mut(nl);
let t = mul(al, bl);
let u = mul(ah, bh);
let mut alh = ah.to_vec();
let mut blh = bh.to_vec();
for i in 0..nl {
alh[i] += al[i].clone();
blh[i] += bl[i].clone();
}
let mut res = vec![T::default(); n + n - 1];
let mut v = mul(&mut alh, &mut blh);
for (i, ti) in t.iter().enumerate() {
v[i] -= ti.clone();
res[i] += ti.clone();
}
for (i, ui) in u.iter().enumerate() {
v[i] -= ui.clone();
res[nl + nl + i] += ui.clone();
}
if nl != nh {
v.pop();
}
for (i, vi) in v.into_iter().enumerate() {
res[nl + i] += vi;
}
res
}
#[test]
fn test() {
let mut it =
std::iter::successors(Some(14025256_i64), |&i| Some(i * i % 20300713))
.map(|i| i % 10);
let n = 1024;
let a: Vec<_> = (0..n).map(|_| it.next().unwrap()).collect();
let b: Vec<_> = (0..n).map(|_| it.next().unwrap()).collect();
let mut expected = vec![0; n + n - 1];
for (i, &ai) in a.iter().enumerate() {
for (j, &bj) in b.iter().enumerate() {
expected[i + j] += ai * bj;
}
}
let actual = convolve(&a, &b);
assert_eq!(actual, expected);
}