use crate::fast::Arithmetic;
use crate::poly::ModPoly;
use polycore::modp::{add, inv, mul};
use polycore::sample::Rng;
use zippel_interp::poly::power_table;
pub(crate) fn degree_bounds(f: &ModPoly, g: &ModPoly, p: u64, rng: &mut Rng) -> Option<Vec<usize>> {
let field = Arithmetic { p };
let point: Vec<_> = (0..f.n).map(|_| rng.nonzero(p)).collect();
let aa = univariate_images(f, &point, p);
let bb = univariate_images(g, &point, p);
aa.iter()
.zip(&bb)
.map(|(a, b)| {
if a.last() == Some(&0) || b.last() == Some(&0) {
return None;
}
Some(field.gcd(a, b).len() - 1)
})
.collect()
}
pub(crate) fn univariate_images(f: &ModPoly, point: &[u64], p: u64) -> Vec<Vec<u64>> {
let degrees = f.degrees();
let powers = power_table(point, °rees, p);
let inverse_point: Vec<_> = point.iter().map(|&b| inv(b, p)).collect();
let inverses = power_table(&inverse_point, °rees, p);
let mut images: Vec<_> = degrees.iter().map(|&d| vec![0; d + 1]).collect();
for (e, c) in &f.terms {
let value = e
.iter()
.zip(&powers)
.fold(*c, |v, (&e, pw)| mul(v, pw[e as usize], p));
for (k, &e) in e.iter().enumerate() {
images[k][e as usize] = add(
images[k][e as usize],
mul(value, inverses[k][e as usize], p),
p,
);
}
}
images
}