haar_lib/math/fps/
sqrt.rs1use crate::num::ff::*;
3use crate::{
4 math::prime_mod::PrimeMod,
5 math::{fps::inv::FpsInv, mod_ops::sqrt::mod_sqrt, polynomial::Polynomial},
6 num::const_modint::ConstModInt,
7};
8
9pub trait FpsSqrt {
11 type Output;
13
14 fn fps_sqrt(self) -> Result<Self::Output, &'static str>;
16}
17
18impl<P: PrimeMod> FpsSqrt for Polynomial<P> {
19 type Output = Self;
20
21 fn fps_sqrt(self) -> Result<Self::Output, &'static str> {
22 let f: Vec<_> = self.into();
23
24 let n = f.len();
25 let k = f
26 .iter()
27 .enumerate()
28 .find(|(_, &x)| x.value() != 0)
29 .map_or(n, |(k, _)| k);
30
31 if k == n {
32 return Ok(f.into());
33 }
34 if k % 2 == 1 {
35 return Err("最小次数が偶数ではない。");
36 }
37
38 let x = mod_sqrt(f[k].value() as u64, P::PRIME_NUM as u64)
39 .ok_or("最小次数項の係数に平方根が存在しない。")?;
40 let m = n - k;
41
42 let half = ConstModInt::new(2).inv();
43 let mut t = 1;
44 let mut ret = vec![ConstModInt::new(x as u32)];
45
46 loop {
47 let mut f = f[k..k + t.min(m)].to_vec();
48 f.resize(t, 0.into());
49
50 ret.resize(t, 0.into());
51 let h = Self::from(ret.clone()).fps_inv()?;
52 let h = Self::from(f) * h;
53 let h: Vec<_> = h.into();
54
55 for (x, y) in ret.iter_mut().zip(h) {
56 *x = (*x + y) * half;
57 }
58
59 if t >= m {
60 break;
61 }
62
63 t <<= 1;
64 }
65
66 ret.resize(n, 0.into());
67 let mut ret: Self = ret.into();
68 ret.shift_higher(k / 2);
69 Ok(ret)
70 }
71}