use crate::{
local_num::{LocalInteger, LocalOne},
mapping::Differentiable,
normed::Normed,
traits::HasApproximateDigits,
ZAdic,
};
use super::{euclid, zadic_wrapper, Polynomial};
pub fn raw_square_free_decomposition<T>(poly: &Polynomial<T>) -> Vec<Polynomial<T>>
where T: Clone + LocalInteger {
square_free_decomposition(poly)
}
pub fn primitive_square_free_decomposition<T>(poly: &Polynomial<T>) -> Vec<Polynomial<T>>
where T: Clone + LocalInteger + Normed, T::Unit: LocalOne {
square_free_decomposition(poly).into_iter().map(Polynomial::primitive_monic).collect()
}
fn square_free_decomposition<T>(poly: &Polynomial<T>) -> Vec<Polynomial<T>>
where T: Clone + LocalInteger {
let mut factors = vec![];
let mut a = poly.clone();
let mut b = a.derivative();
let mut gcd = euclid::factored_pseudo_rem_gcd(a.clone(), b.clone());
while a.degree().is_some_and(|db| db != 0) {
let (quotient0, _, mult0) = euclid::euclidean_pseudo_div(a.clone(), &gcd);
let (quotient1, _, mult1) = euclid::euclidean_pseudo_div(b.clone(), &gcd);
a = quotient0.mul_coefficients(mult1);
b = quotient1.mul_coefficients(mult0) - a.derivative();
gcd = euclid::factored_pseudo_rem_gcd(a.clone(), b.clone());
factors.push(gcd.clone());
}
factors.pop();
let factors = factors.into_iter().map(Polynomial::factor_coefficients).collect();
factors
}
pub fn zadic_square_free_decomposition(poly: &Polynomial<ZAdic>) -> Vec<Polynomial<ZAdic>> {
if poly.coefficients().all(HasApproximateDigits::is_certain) {
return primitive_square_free_decomposition(poly);
}
let wrapped_poly = zadic_wrapper::wrap_poly(poly.clone());
let mut factors = vec![];
let mut a = wrapped_poly.clone();
let mut b = a.derivative();
let mut gcd = euclid::primitive_pseudo_rem_gcd(a.clone(), b.clone());
while a.degree().is_some_and(|db| db != 0) {
let (quotient0, _, mult0) = euclid::euclidean_pseudo_div(a.clone(), &gcd);
let (quotient1, _, mult1) = euclid::euclidean_pseudo_div(b.clone(), &gcd);
a = quotient0.mul_coefficients(mult1);
b = quotient1.mul_coefficients(mult0) - a.derivative();
gcd = euclid::primitive_pseudo_rem_gcd(a.clone(), b.clone());
factors.push(gcd.clone());
}
factors.pop();
factors.into_iter().map(|poly| {
let unwrapped_poly = Polynomial::new(poly.into_coefficients().map(|z| z.0).collect());
unwrapped_poly.primitive_monic()
}).collect()
}