haar_lib/math/polynomial/
polynomial_taylor_shift.rs1use crate::math::polynomial::*;
7use crate::math::prime_mod::PrimeMod;
8use crate::num::const_modint::*;
9
10pub trait TaylorShift {
12 type Value;
14
15 fn taylor_shift(self, c: Self::Value) -> Self;
19}
20
21impl<P: PrimeMod> TaylorShift for Polynomial<P> {
22 type Value = ConstModInt<P>;
23
24 fn taylor_shift(self, c: Self::Value) -> Self {
25 let p: Vec<_> = self.into();
26 let n = p.len();
27 let mut f = ConstModInt::new(1);
28
29 let mut a = vec![ConstModInt::new(0); 2 * n - 1];
30 for (i, (a, p)) in a.iter_mut().skip(n - 1).zip(p.into_iter()).enumerate() {
31 if i != 0 {
32 f *= ConstModInt::new(i as u32);
33 }
34 *a = p * f;
35 }
36
37 let mut g = vec![ConstModInt::new(0); n];
38 g[n - 1] = f.inv();
39 for i in (0..n - 1).rev() {
40 g[i] = g[i + 1] * ConstModInt::new(i as u32 + 1);
41 }
42
43 let mut d = ConstModInt::new(1);
44 let mut b = vec![ConstModInt::new(0); 2 * n - 1];
45 for (b, g) in b.iter_mut().take(n).rev().zip(g.iter()) {
46 *b = d * *g;
47 d *= c;
48 }
49
50 let c = Self::NTT.convolve(a, b);
51 c.into_iter()
52 .skip((n - 1) * 2)
53 .zip(g)
54 .map(|(c, g)| c * g)
55 .collect::<Vec<_>>()
56 .into()
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::math::prime_mod::Prime;
63
64 use super::*;
65
66 type P = Prime<998244353>;
67
68 #[test]
69 fn test() {
70 let coeffs = vec![1, 2, 3, 4, 5];
71 let c = 3;
72
73 let res = Polynomial::<P>::from(coeffs.clone()).taylor_shift(c.into());
74
75 let mut ans = Polynomial::zero();
76 for (i, a) in coeffs.into_iter().enumerate() {
77 let mut p = Polynomial::<P>::from(vec![c, 1]).pow(i as u64);
78 p.scale(a.into());
79 ans += p;
80 }
81
82 assert_eq!(res, ans);
83 }
84}