1use crate::computation::ComputationController;
2use crate::ring::*;
3use crate::divisibility::*;
4
5pub trait PrincipalIdealRing: DivisibilityRing {
13
14 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element>;
29
30 fn annihilator(&self, val: &Self::Element) -> Self::Element {
48 self.checked_div_min(&self.zero(), val).unwrap()
49 }
50
51 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element);
62
63 #[stability::unstable(feature = "enable")]
68 fn create_elimination_matrix(&self, a: &Self::Element, b: &Self::Element) -> ([Self::Element; 4], Self::Element) {
69 assert!(self.is_commutative());
70 let old_gcd = self.ideal_gen(a, b);
71 let new_a = self.checked_div_min(a, &old_gcd).unwrap();
72 let new_b = self.checked_div_min(b, &old_gcd).unwrap();
73 let (s, t, gcd_new) = self.extended_ideal_gen(&new_a, &new_b);
74 debug_assert!(self.is_unit(&gcd_new));
75
76 let subtract_factor = self.checked_left_div(&self.sub(self.mul_ref(b, &new_a), self.mul_ref(a, &new_b)), &gcd_new).unwrap();
77 let mut result = [s, t, self.negate(new_b), new_a];
79
80 let sub1 = self.mul_ref(&result[0], &subtract_factor);
81 self.sub_assign(&mut result[2], sub1);
82 let sub2 = self.mul_ref_fst(&result[1], subtract_factor);
83 self.sub_assign(&mut result[3], sub2);
84 debug_assert!(self.is_unit(&self.sub(self.mul_ref(&result[0], &result[3]), self.mul_ref(&result[1], &result[2]))));
85 return (result, gcd_new);
86 }
87
88
89 fn ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
97 self.extended_ideal_gen(lhs, rhs).2
98 }
99
100 fn ideal_gen_with_controller<Controller>(&self, lhs: &Self::Element, rhs: &Self::Element, _: Controller) -> Self::Element
106 where Controller: ComputationController
107 {
108 self.ideal_gen(lhs, rhs)
109 }
110
111 fn lcm(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
120 self.checked_left_div(&self.mul_ref(lhs, rhs), &self.ideal_gen(lhs, rhs)).unwrap()
121 }
122}
123
124pub trait PrincipalIdealRingStore: RingStore
129 where Self::Type: PrincipalIdealRing
130{
131 delegate!{ PrincipalIdealRing, fn checked_div_min(&self, lhs: &El<Self>, rhs: &El<Self>) -> Option<El<Self>> }
132 delegate!{ PrincipalIdealRing, fn extended_ideal_gen(&self, lhs: &El<Self>, rhs: &El<Self>) -> (El<Self>, El<Self>, El<Self>) }
133 delegate!{ PrincipalIdealRing, fn ideal_gen(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
134 delegate!{ PrincipalIdealRing, fn annihilator(&self, val: &El<Self>) -> El<Self> }
135 delegate!{ PrincipalIdealRing, fn lcm(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
136
137 fn gcd(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> {
141 self.ideal_gen(lhs, rhs)
142 }
143}
144
145impl<R> PrincipalIdealRingStore for R
146 where R: RingStore,
147 R::Type: PrincipalIdealRing
148{}
149
150pub trait EuclideanRing: PrincipalIdealRing {
172
173 fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element);
181
182 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize>;
186
187 fn euclidean_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
195 self.euclidean_div_rem(lhs, rhs).0
196 }
197
198 fn euclidean_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
206 self.euclidean_div_rem(lhs, rhs).1
207 }
208}
209
210pub trait EuclideanRingStore: RingStore + DivisibilityRingStore
214 where Self::Type: EuclideanRing
215{
216 delegate!{ EuclideanRing, fn euclidean_div_rem(&self, lhs: El<Self>, rhs: &El<Self>) -> (El<Self>, El<Self>) }
217 delegate!{ EuclideanRing, fn euclidean_div(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
218 delegate!{ EuclideanRing, fn euclidean_rem(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
219 delegate!{ EuclideanRing, fn euclidean_deg(&self, val: &El<Self>) -> Option<usize> }
220}
221
222impl<R> EuclideanRingStore for R
223 where R: RingStore, R::Type: EuclideanRing
224{}
225
226#[allow(missing_docs)]
227#[cfg(any(test, feature = "generic_tests"))]
228pub mod generic_tests {
229 use super::*;
230 use crate::{algorithms::int_factor::factor, homomorphism::Homomorphism, integer::{int_cast, BigIntRing, IntegerRingStore}, ordered::OrderedRingStore, primitive_int::StaticRing, ring::El};
231
232 pub fn test_euclidean_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
233 where R::Type: EuclideanRing
234 {
235 assert!(ring.is_commutative());
236 assert!(ring.is_noetherian());
237 let elements = edge_case_elements.collect::<Vec<_>>();
238 for a in &elements {
239 for b in &elements {
240 if ring.is_zero(b) {
241 continue;
242 }
243 let (q, r) = ring.euclidean_div_rem(ring.clone_el(a), b);
244 assert!(ring.euclidean_deg(b).is_none() || ring.euclidean_deg(&r).unwrap_or(usize::MAX) < ring.euclidean_deg(b).unwrap());
245 assert_el_eq!(ring, a, ring.add(ring.mul(q, ring.clone_el(b)), r));
246 }
247 }
248 }
249
250 pub fn test_principal_ideal_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
251 where R::Type: PrincipalIdealRing
252 {
253 assert!(ring.is_commutative());
254 assert!(ring.is_noetherian());
255 let elements = edge_case_elements.collect::<Vec<_>>();
256
257 let expected_unit = ring.checked_div_min(&ring.zero(), &ring.zero()).unwrap();
258 assert!(ring.is_unit(&expected_unit), "checked_div_min() returned a non-minimal quotient {} * {} = {}", ring.format(&expected_unit), ring.format(&ring.zero()), ring.format(&ring.zero()));
259 let expected_zero = ring.checked_div_min(&ring.zero(), &ring.one()).unwrap();
260 assert!(ring.is_zero(&expected_zero), "checked_div_min() returned a wrong quotient {} * {} = {}", ring.format(&expected_zero), ring.format(&ring.one()), ring.format(&ring.zero()));
261
262 for a in &elements {
263 let expected_unit = ring.checked_div_min(a, a).unwrap();
264 assert!(ring.is_unit(&expected_unit), "checked_div_min() returned a non-minimal quotient {} * {} = {}", ring.format(&expected_unit), ring.format(a), ring.format(a));
265 }
266
267 for a in &elements {
268 for b in &elements {
269 for c in &elements {
270 let g1 = ring.mul_ref(a, b);
271 let g2 = ring.mul_ref(a, c);
272 let (s, t, g) = ring.extended_ideal_gen(&g1, &g2);
273 assert!(ring.checked_div(&g, a).is_some(), "Wrong ideal generator: ({}) contains the ideal I = ({}, {}), but extended_ideal_gen() found a generator I = ({}) that does not satisfy {} | {}", ring.format(a), ring.format(&g1), ring.format(&g2), ring.format(&g), ring.format(a), ring.format(&g));
274 assert_el_eq!(ring, g, ring.add(ring.mul_ref(&s, &g1), ring.mul_ref(&t, &g2)));
275 }
276 }
277 }
278 for a in &elements {
279 for b in &elements {
280 let g1 = ring.mul_ref(a, b);
281 let g2 = ring.mul_ref_fst(a, ring.add_ref_fst(b, ring.one()));
282 let (s, t, g) = ring.extended_ideal_gen(&g1, &g2);
283 assert!(ring.checked_div(&g, a).is_some() && ring.checked_div(a, &g).is_some(), "Expected ideals ({}) and I = ({}, {}) to be equal, but extended_ideal_gen() returned generator {} of I", ring.format(a), ring.format(&g1), ring.format(&g2), ring.format(&g));
284 assert_el_eq!(ring, g, ring.add(ring.mul_ref(&s, &g1), ring.mul_ref(&t, &g2)));
285 }
286 }
287
288 let ZZbig = BigIntRing::RING;
289 let char = ring.characteristic(ZZbig).unwrap();
290 if !ZZbig.is_zero(&char) && ZZbig.is_leq(&char, &ZZbig.power_of_two(30)) {
291 let p = factor(ZZbig, ZZbig.clone_el(&char)).into_iter().next().unwrap().0;
292 let expected = ring.int_hom().map(int_cast(ZZbig.checked_div(&char, &p).unwrap(), StaticRing::<i32>::RING, ZZbig));
293 let ann_p = ring.annihilator(&ring.int_hom().map(int_cast(p, StaticRing::<i32>::RING, ZZbig)));
294 assert!(ring.checked_div(&ann_p, &expected).is_some());
295 assert!(ring.checked_div(&expected, &ann_p).is_some());
296 }
297 }
298}