haar_lib/math/convolution/
subset_conv.rs1use crate::math::convolution::{mobius::*, zeta::*};
7use std::ops::{Add, Mul, Sub};
8
9#[allow(clippy::needless_range_loop, clippy::manual_memcpy)]
12pub fn subset_convolution<T>(f: Vec<T>, g: Vec<T>) -> Vec<T>
13where
14 T: Copy + Default + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
15{
16 assert_eq!(f.len(), g.len());
17
18 let n = f.len();
19 assert!(n.is_power_of_two());
20
21 let k = n.trailing_zeros() as usize;
22
23 let mut f2 = vec![vec![T::default(); n]; k + 1];
24 let mut g2 = vec![vec![T::default(); n]; k + 1];
25
26 for j in 0..n {
27 let i = j.count_ones() as usize;
28 f2[i][j] = f[j];
29 g2[i][j] = g[j];
30 }
31
32 for i in 0..=k {
33 fast_zeta_subset(&mut f2[i]);
34 fast_zeta_subset(&mut g2[i]);
35 }
36
37 let mut h = vec![vec![T::default(); n]; k + 1];
38
39 for i in 0..=k {
40 for s in 0..=i {
41 for j in 0..n {
42 h[i][j] = h[i][j] + f2[s][j] * g2[i - s][j];
43 }
44 }
45 }
46
47 for i in 0..=k {
48 fast_mobius_subset(&mut h[i]);
49 }
50
51 (0..n)
52 .map(|j| {
53 let i = j.count_ones() as usize;
54 h[i][j]
55 })
56 .collect()
57}