feanor_math/algorithms/poly_factor/
extension.rs1use crate::algorithms;
2use crate::algorithms::poly_factor::FactorPolyField;
3use crate::algorithms::poly_gcd::PolyTFracGCDRing;
4use crate::compute_locally::InterpolationBaseRing;
5use crate::field::*;
6use crate::homomorphism::*;
7use crate::ordered::OrderedRingStore;
8use crate::pid::EuclideanRing;
9use crate::primitive_int::StaticRing;
10use crate::ring::*;
11use crate::rings::extension::FreeAlgebra;
12use crate::rings::extension::FreeAlgebraStore;
13use crate::rings::poly::dense_poly::DensePolyRing;
14use crate::rings::poly::{PolyRing, PolyRingStore};
15use crate::integer::*;
16use crate::MAX_PROBABILISTIC_REPETITIONS;
17use crate::specialization::FiniteRingSpecializable;
18
19#[stability::unstable(feature = "enable")]
20pub struct ProbablyNotSquarefree;
21
22#[stability::unstable(feature = "enable")]
30pub fn poly_factor_squarefree_extension<P>(LX: P, f: &El<P>, attempts: usize) -> Result<Vec<El<P>>, ProbablyNotSquarefree>
31 where P: RingStore,
32 P::Type: PolyRing + EuclideanRing,
33 <<P::Type as RingExtension>::BaseRing as RingStore>::Type: Field + FreeAlgebra + PolyTFracGCDRing,
34 <<<<P::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing as RingStore>::Type: PerfectField + PolyTFracGCDRing + FactorPolyField + InterpolationBaseRing + FiniteRingSpecializable
35{
36 let L = LX.base_ring();
37 let K = L.base_ring();
38
39 assert!(LX.base_ring().is_one(LX.lc(f).unwrap()));
40
41 let KX = DensePolyRing::new(K, "X");
42 let KXY = DensePolyRing::new(KX.clone(), "Y");
44
45 let Norm = |f: El<P>| {
46 let f_over_KY = <_ as RingStore>::sum(&KXY,
47 LX.terms(&f).map(|(c, i)| {
48 let mut result = L.poly_repr(&KXY, c, KX.inclusion());
49 KXY.inclusion().mul_assign_map(&mut result, KX.pow(KX.indeterminate(), i));
50 result
51 })
52 );
53 let gen_poly = L.generating_poly(&KXY, KX.inclusion());
54
55 return algorithms::resultant::resultant_local::<&DensePolyRing<_>>(&KXY, f_over_KY, gen_poly);
56 };
57
58 let ZZbig = BigIntRing::RING;
75 let characteristic = K.characteristic(&ZZbig).unwrap();
76 let bound = LX.degree(f).unwrap() * LX.degree(f).unwrap() * L.rank();
78 assert!(ZZbig.is_zero(&characteristic) || ZZbig.is_geq(&characteristic, &int_cast(bound as i64, ZZbig, StaticRing::<i64>::RING)));
79
80 let mut rng = oorandom::Rand64::new(1);
81
82 for _ in 0..attempts {
83 let k = StaticRing::<i32>::RING.get_uniformly_random(&(bound as i32), || rng.rand_u64());
84 let lin_transform = LX.from_terms([(L.mul(L.canonical_gen(), L.int_hom().map(k)), 0), (L.one(), 1)].into_iter());
85 let f_transformed = LX.evaluate(f, &lin_transform, &LX.inclusion());
86
87 let norm_f_transformed = Norm(LX.clone_el(&f_transformed));
88 let degree = KX.degree(&norm_f_transformed).unwrap();
89 let squarefree_part = <_ as PolyTFracGCDRing>::squarefree_part(&KX, &norm_f_transformed);
90
91 if KX.degree(&squarefree_part).unwrap() == degree {
92 let lin_transform_rev = LX.from_terms([(L.mul(L.canonical_gen(), L.int_hom().map(-k)), 0), (L.one(), 1)].into_iter());
93 let (factorization, _unit) = <_ as FactorPolyField>::factor_poly(&KX, &squarefree_part);
94
95 return Ok(factorization.into_iter().map(|(factor, e)| {
96 assert!(e == 1);
97 let f_factor = LX.normalize(<_ as PolyTFracGCDRing>::gcd(&LX, &f_transformed, &LX.lifted_hom(&KX, L.inclusion()).map(factor)));
98 return LX.evaluate(&f_factor, &lin_transform_rev, &LX.inclusion());
99 }).collect());
100 }
101 }
102 return Err(ProbablyNotSquarefree);
103}
104
105#[stability::unstable(feature = "enable")]
110pub fn poly_factor_extension<P>(poly_ring: P, f: &El<P>) -> (Vec<(El<P>, usize)>, El<<P::Type as RingExtension>::BaseRing>)
111 where P: RingStore,
112 P::Type: PolyRing + EuclideanRing,
113 <<P::Type as RingExtension>::BaseRing as RingStore>::Type: FreeAlgebra + PerfectField + FiniteRingSpecializable + PolyTFracGCDRing,
114 <<<<P::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing as RingStore>::Type: PerfectField + PolyTFracGCDRing + FactorPolyField + InterpolationBaseRing + FiniteRingSpecializable
115{
116 let KX = &poly_ring;
117 let K = KX.base_ring();
118
119 assert!(!KX.is_zero(f));
130 let mut result: Vec<(El<P>, usize)> = Vec::new();
131 for (non_irred_factor, k) in <_ as PolyTFracGCDRing>::power_decomposition(KX, f) {
132 for factor in poly_factor_squarefree_extension(KX, &non_irred_factor, MAX_PROBABILISTIC_REPETITIONS).ok().unwrap() {
133 if let Some((i, _)) = result.iter().enumerate().filter(|(_, f)| KX.eq_el(&f.0, &factor)).next() {
134 result[i].1 += k;
135 } else {
136 result.push((factor, k));
137 }
138 }
139 }
140 return (result, K.clone_el(KX.coefficient_at(f, 0)));
141}