feanor_math/algorithms/poly_factor/
extension.rs1use crate::MAX_PROBABILISTIC_REPETITIONS;
2use crate::algorithms::poly_factor::FactorPolyField;
3use crate::algorithms::poly_gcd::PolyTFracGCDRing;
4use crate::algorithms::resultant::ComputeResultantRing;
5use crate::computation::*;
6use crate::field::*;
7use crate::homomorphism::*;
8use crate::integer::*;
9use crate::ordered::OrderedRingStore;
10use crate::pid::EuclideanRing;
11use crate::primitive_int::StaticRing;
12use crate::reduce_lift::poly_eval::InterpolationBaseRing;
13use crate::ring::*;
14use crate::rings::extension::{FreeAlgebra, FreeAlgebraStore};
15use crate::rings::poly::dense_poly::DensePolyRing;
16use crate::rings::poly::{PolyRing, PolyRingStore};
17use crate::specialization::FiniteRingSpecializable;
18
19#[stability::unstable(feature = "enable")]
20pub struct ProbablyNotSquarefree;
21
22#[stability::unstable(feature = "enable")]
28pub fn poly_factor_squarefree_extension<P, Controller>(
29 LX: P,
30 f: &El<P>,
31 attempts: usize,
32 controller: Controller,
33) -> Result<Vec<El<P>>, ProbablyNotSquarefree>
34where
35 P: RingStore,
36 P::Type: PolyRing + EuclideanRing,
37 <<P::Type as RingExtension>::BaseRing as RingStore>::Type: Field + FreeAlgebra + PolyTFracGCDRing,
38 <<<<P::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing as RingStore>::Type:
39 PerfectField + PolyTFracGCDRing + FactorPolyField + InterpolationBaseRing + FiniteRingSpecializable + SelfIso,
40 Controller: ComputationController,
41{
42 controller.run_computation(
43 format_args!(
44 "factor_ring_ext(pdeg={}, extdeg={})",
45 LX.degree(f).unwrap(),
46 LX.base_ring().rank()
47 ),
48 |controller| {
49 let L = LX.base_ring();
50 let K = L.base_ring();
51
52 assert!(LX.base_ring().is_one(LX.lc(f).unwrap()));
53
54 let KX = DensePolyRing::new(K, "X");
55 let KXY = DensePolyRing::new(KX.clone(), "Y");
57
58 let Norm = |f: El<P>| {
59 let f_over_KY = <_ as RingStore>::sum(
60 &KXY,
61 LX.terms(&f).map(|(c, i)| {
62 let mut result = L.poly_repr(&KXY, c, KX.inclusion());
63 KXY.inclusion()
64 .mul_assign_map(&mut result, KX.pow(KX.indeterminate(), i));
65 result
66 }),
67 );
68 let gen_poly = L.generating_poly(&KXY, KX.inclusion());
69
70 return <_ as ComputeResultantRing>::resultant(&KXY, f_over_KY, gen_poly);
71 };
72
73 let ZZbig = BigIntRing::RING;
97 let characteristic = K.characteristic(&ZZbig).unwrap();
98 let bound = LX.degree(f).unwrap() * LX.degree(f).unwrap() * L.rank();
101 assert!(
102 ZZbig.is_zero(&characteristic)
103 || ZZbig.is_geq(
104 &characteristic,
105 &int_cast(bound.try_into().unwrap(), ZZbig, StaticRing::<i64>::RING)
106 )
107 );
108
109 let mut rng = oorandom::Rand64::new(1);
110
111 for _ in 0..attempts {
112 let k = StaticRing::<i32>::RING.get_uniformly_random(&bound.try_into().unwrap(), || rng.rand_u64());
113 let lin_transform = LX.from_terms([(L.mul(L.canonical_gen(), L.int_hom().map(k)), 0), (L.one(), 1)]);
114 let f_transformed = LX.evaluate(f, &lin_transform, LX.inclusion());
115
116 let norm_f_transformed = Norm(LX.clone_el(&f_transformed));
117 log_progress!(controller, "(norm)");
118 let degree = KX.degree(&norm_f_transformed).unwrap();
119 let squarefree_part = <_ as PolyTFracGCDRing>::squarefree_part(&KX, &norm_f_transformed);
120 log_progress!(controller, "(squarefree)");
121
122 if KX.degree(&squarefree_part).unwrap() == degree {
123 let lin_transform_rev =
124 LX.from_terms([(L.mul(L.canonical_gen(), L.int_hom().map(-k)), 0), (L.one(), 1)]);
125 let (factorization, _unit) =
126 <_ as FactorPolyField>::factor_poly_with_controller(&KX, &squarefree_part, controller.clone());
127 log_progress!(controller, "(factored)");
128
129 return Ok(factorization
130 .into_iter()
131 .map(|(factor, e)| {
132 assert!(e == 1);
133 let f_factor = LX.normalize(<_ as PolyTFracGCDRing>::gcd(
134 &LX,
135 &f_transformed,
136 &LX.lifted_hom(&KX, L.inclusion()).map(factor),
137 ));
138 return LX.evaluate(&f_factor, &lin_transform_rev, LX.inclusion());
139 })
140 .collect());
141 }
142 }
143 return Err(ProbablyNotSquarefree);
144 },
145 )
146}
147
148#[stability::unstable(feature = "enable")]
151pub fn poly_factor_extension<P, Controller>(
152 poly_ring: P,
153 f: &El<P>,
154 controller: Controller,
155) -> (Vec<(El<P>, usize)>, El<<P::Type as RingExtension>::BaseRing>)
156where
157 P: RingStore,
158 P::Type: PolyRing + EuclideanRing,
159 <<P::Type as RingExtension>::BaseRing as RingStore>::Type:
160 FreeAlgebra + PerfectField + FiniteRingSpecializable + PolyTFracGCDRing,
161 <<<<P::Type as RingExtension>::BaseRing as RingStore>::Type as RingExtension>::BaseRing as RingStore>::Type:
162 PerfectField + PolyTFracGCDRing + FactorPolyField + InterpolationBaseRing + FiniteRingSpecializable + SelfIso,
163 Controller: ComputationController,
164{
165 let KX = &poly_ring;
166 let K = KX.base_ring();
167
168 assert!(!KX.is_zero(f));
179 let mut result: Vec<(El<P>, usize)> = Vec::new();
180 for (non_irred_factor, k) in <_ as PolyTFracGCDRing>::power_decomposition(KX, f) {
181 for factor in
182 poly_factor_squarefree_extension(KX, &non_irred_factor, MAX_PROBABILISTIC_REPETITIONS, controller.clone())
183 .ok()
184 .unwrap()
185 {
186 if let Some((i, _)) = result.iter().enumerate().find(|(_, f)| KX.eq_el(&f.0, &factor)) {
187 result[i].1 += k;
188 } else {
189 result.push((factor, k));
190 }
191 }
192 }
193 return (result, K.clone_el(KX.coefficient_at(f, 0)));
194}