1use crate::ring::*;
2use crate::divisibility::*;
3
4pub trait PrincipalIdealRing: DivisibilityRing {
12
13 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element>;
28
29 fn annihilator(&self, val: &Self::Element) -> Self::Element {
47 self.checked_div_min(&self.zero(), val).unwrap()
48 }
49
50 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element);
61
62 #[stability::unstable(feature = "enable")]
67 fn create_elimination_matrix(&self, a: &Self::Element, b: &Self::Element) -> ([Self::Element; 4], Self::Element) {
68 assert!(self.is_commutative());
69 let old_gcd = self.ideal_gen(a, b);
70 let new_a = self.checked_div_min(a, &old_gcd).unwrap();
71 let new_b = self.checked_div_min(b, &old_gcd).unwrap();
72 let (s, t, gcd_new) = self.extended_ideal_gen(&new_a, &new_b);
73 debug_assert!(self.is_unit(&gcd_new));
74
75 let subtract_factor = self.checked_left_div(&self.sub(self.mul_ref(b, &new_a), self.mul_ref(a, &new_b)), &gcd_new).unwrap();
76 let mut result = [s, t, self.negate(new_b), new_a];
78
79 let sub1 = self.mul_ref(&result[0], &subtract_factor);
80 self.sub_assign(&mut result[2], sub1);
81 let sub2 = self.mul_ref_fst(&result[1], subtract_factor);
82 self.sub_assign(&mut result[3], sub2);
83 debug_assert!(self.is_unit(&self.sub(self.mul_ref(&result[0], &result[3]), self.mul_ref(&result[1], &result[2]))));
84 return (result, gcd_new);
85 }
86
87
88 fn ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
96 self.extended_ideal_gen(lhs, rhs).2
97 }
98
99 fn lcm(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
108 self.checked_left_div(&self.mul_ref(lhs, rhs), &self.ideal_gen(lhs, rhs)).unwrap()
109 }
110}
111
112pub trait PrincipalIdealRingStore: RingStore
117 where Self::Type: PrincipalIdealRing
118{
119 delegate!{ PrincipalIdealRing, fn checked_div_min(&self, lhs: &El<Self>, rhs: &El<Self>) -> Option<El<Self>> }
120 delegate!{ PrincipalIdealRing, fn extended_ideal_gen(&self, lhs: &El<Self>, rhs: &El<Self>) -> (El<Self>, El<Self>, El<Self>) }
121 delegate!{ PrincipalIdealRing, fn ideal_gen(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
122 delegate!{ PrincipalIdealRing, fn annihilator(&self, val: &El<Self>) -> El<Self> }
123 delegate!{ PrincipalIdealRing, fn lcm(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
124
125 fn gcd(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> {
129 self.ideal_gen(lhs, rhs)
130 }
131}
132
133impl<R> PrincipalIdealRingStore for R
134 where R: RingStore,
135 R::Type: PrincipalIdealRing
136{}
137
138pub trait EuclideanRing: PrincipalIdealRing {
160
161 fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element);
169
170 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize>;
174
175 fn euclidean_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
183 self.euclidean_div_rem(lhs, rhs).0
184 }
185
186 fn euclidean_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
194 self.euclidean_div_rem(lhs, rhs).1
195 }
196}
197
198pub trait EuclideanRingStore: RingStore + DivisibilityRingStore
202 where Self::Type: EuclideanRing
203{
204 delegate!{ EuclideanRing, fn euclidean_div_rem(&self, lhs: El<Self>, rhs: &El<Self>) -> (El<Self>, El<Self>) }
205 delegate!{ EuclideanRing, fn euclidean_div(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
206 delegate!{ EuclideanRing, fn euclidean_rem(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
207 delegate!{ EuclideanRing, fn euclidean_deg(&self, val: &El<Self>) -> Option<usize> }
208}
209
210impl<R> EuclideanRingStore for R
211 where R: RingStore, R::Type: EuclideanRing
212{}
213
214#[allow(missing_docs)]
215#[cfg(any(test, feature = "generic_tests"))]
216pub mod generic_tests {
217 use super::*;
218 use crate::{algorithms::int_factor::factor, homomorphism::Homomorphism, integer::{int_cast, BigIntRing, IntegerRingStore}, ordered::OrderedRingStore, primitive_int::StaticRing, ring::El};
219
220 pub fn test_euclidean_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
221 where R::Type: EuclideanRing
222 {
223 assert!(ring.is_commutative());
224 assert!(ring.is_noetherian());
225 let elements = edge_case_elements.collect::<Vec<_>>();
226 for a in &elements {
227 for b in &elements {
228 if ring.is_zero(b) {
229 continue;
230 }
231 let (q, r) = ring.euclidean_div_rem(ring.clone_el(a), b);
232 assert!(ring.euclidean_deg(b).is_none() || ring.euclidean_deg(&r).unwrap_or(usize::MAX) < ring.euclidean_deg(b).unwrap());
233 assert_el_eq!(ring, a, ring.add(ring.mul(q, ring.clone_el(b)), r));
234 }
235 }
236 }
237
238 pub fn test_principal_ideal_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
239 where R::Type: PrincipalIdealRing
240 {
241 assert!(ring.is_commutative());
242 assert!(ring.is_noetherian());
243 let elements = edge_case_elements.collect::<Vec<_>>();
244
245 let expected_unit = ring.checked_div_min(&ring.zero(), &ring.zero()).unwrap();
246 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()));
247 let expected_zero = ring.checked_div_min(&ring.zero(), &ring.one()).unwrap();
248 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()));
249
250 for a in &elements {
251 let expected_unit = ring.checked_div_min(a, a).unwrap();
252 assert!(ring.is_unit(&expected_unit), "checked_div_min() returned a non-minimal quotient {} * {} = {}", ring.format(&expected_unit), ring.format(a), ring.format(a));
253 }
254
255 for a in &elements {
256 for b in &elements {
257 for c in &elements {
258 let g1 = ring.mul_ref(a, b);
259 let g2 = ring.mul_ref(a, c);
260 let (s, t, g) = ring.extended_ideal_gen(&g1, &g2);
261 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));
262 assert_el_eq!(ring, g, ring.add(ring.mul_ref(&s, &g1), ring.mul_ref(&t, &g2)));
263 }
264 }
265 }
266 for a in &elements {
267 for b in &elements {
268 let g1 = ring.mul_ref(a, b);
269 let g2 = ring.mul_ref_fst(a, ring.add_ref_fst(b, ring.one()));
270 let (s, t, g) = ring.extended_ideal_gen(&g1, &g2);
271 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));
272 assert_el_eq!(ring, g, ring.add(ring.mul_ref(&s, &g1), ring.mul_ref(&t, &g2)));
273 }
274 }
275
276 let ZZbig = BigIntRing::RING;
277 let char = ring.characteristic(ZZbig).unwrap();
278 if !ZZbig.is_zero(&char) && ZZbig.is_leq(&char, &ZZbig.power_of_two(30)) {
279 let p = factor(ZZbig, ZZbig.clone_el(&char)).into_iter().next().unwrap().0;
280 let expected = ring.int_hom().map(int_cast(ZZbig.checked_div(&char, &p).unwrap(), StaticRing::<i32>::RING, ZZbig));
281 let ann_p = ring.annihilator(&ring.int_hom().map(int_cast(p, StaticRing::<i32>::RING, ZZbig)));
282 assert!(ring.checked_div(&ann_p, &expected).is_some());
283 assert!(ring.checked_div(&expected, &ann_p).is_some());
284 }
285 }
286}