1use crate::computation::ComputationController;
2use crate::divisibility::*;
3use crate::ring::*;
4
5pub trait PrincipalIdealRing: DivisibilityRing {
11 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element>;
24
25 fn annihilator(&self, val: &Self::Element) -> Self::Element { self.checked_div_min(&self.zero(), val).unwrap() }
45
46 fn extended_ideal_gen(
55 &self,
56 lhs: &Self::Element,
57 rhs: &Self::Element,
58 ) -> (Self::Element, Self::Element, Self::Element);
59
60 #[stability::unstable(feature = "enable")]
63 fn create_elimination_matrix(&self, a: &Self::Element, b: &Self::Element) -> ([Self::Element; 4], Self::Element) {
64 assert!(self.is_commutative());
65 let old_gcd = self.ideal_gen(a, b);
66 let new_a = self.checked_div_min(a, &old_gcd).unwrap();
67 let new_b = self.checked_div_min(b, &old_gcd).unwrap();
68 let (s, t, gcd_new) = self.extended_ideal_gen(&new_a, &new_b);
69 debug_assert!(self.is_unit(&gcd_new));
70
71 let subtract_factor = self
72 .checked_left_div(&self.sub(self.mul_ref(b, &new_a), self.mul_ref(a, &new_b)), &gcd_new)
73 .unwrap();
74 let mut result = [s, t, self.negate(new_b), new_a];
77
78 let sub1 = self.mul_ref(&result[0], &subtract_factor);
79 self.sub_assign(&mut result[2], sub1);
80 let sub2 = self.mul_ref_fst(&result[1], subtract_factor);
81 self.sub_assign(&mut result[3], sub2);
82 debug_assert!(self.is_unit(&self.sub(
83 self.mul_ref(&result[0], &result[3]),
84 self.mul_ref(&result[1], &result[2])
85 )));
86 return (result, gcd_new);
87 }
88
89 fn ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
95 self.extended_ideal_gen(lhs, rhs).2
96 }
97
98 fn ideal_gen_with_controller<Controller>(
102 &self,
103 lhs: &Self::Element,
104 rhs: &Self::Element,
105 _: Controller,
106 ) -> Self::Element
107 where
108 Controller: ComputationController,
109 {
110 self.ideal_gen(lhs, rhs)
111 }
112
113 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))
121 .unwrap()
122 }
123}
124
125pub trait PrincipalIdealRingStore: RingStore
128where
129 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> { self.ideal_gen(lhs, rhs) }
139}
140
141impl<R> PrincipalIdealRingStore for R
142where
143 R: RingStore,
144 R::Type: PrincipalIdealRing,
145{
146}
147
148pub trait EuclideanRing: PrincipalIdealRing {
168 fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element);
174
175 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize>;
177
178 fn euclidean_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
184 self.euclidean_div_rem(lhs, rhs).0
185 }
186
187 fn euclidean_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
193 self.euclidean_div_rem(lhs, rhs).1
194 }
195}
196
197pub trait EuclideanRingStore: RingStore + DivisibilityRingStore
199where
200 Self::Type: EuclideanRing,
201{
202 delegate! { EuclideanRing, fn euclidean_div_rem(&self, lhs: El<Self>, rhs: &El<Self>) -> (El<Self>, El<Self>) }
203 delegate! { EuclideanRing, fn euclidean_div(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
204 delegate! { EuclideanRing, fn euclidean_rem(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
205 delegate! { EuclideanRing, fn euclidean_deg(&self, val: &El<Self>) -> Option<usize> }
206}
207
208impl<R> EuclideanRingStore for R
209where
210 R: RingStore,
211 R::Type: EuclideanRing,
212{
213}
214
215#[allow(missing_docs)]
216#[cfg(any(test, feature = "generic_tests"))]
217pub mod generic_tests {
218 use super::*;
219 use crate::algorithms::int_factor::factor;
220 use crate::homomorphism::Homomorphism;
221 use crate::integer::{BigIntRing, IntegerRingStore, int_cast};
222 use crate::ordered::OrderedRingStore;
223 use crate::primitive_int::StaticRing;
224 use crate::ring::El;
225
226 pub fn test_euclidean_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
227 where
228 R::Type: EuclideanRing,
229 {
230 assert!(ring.is_commutative());
231 assert!(ring.is_noetherian());
232 let elements = edge_case_elements.collect::<Vec<_>>();
233 for a in &elements {
234 for b in &elements {
235 if ring.is_zero(b) {
236 continue;
237 }
238 let (q, r) = ring.euclidean_div_rem(ring.clone_el(a), b);
239 assert!(
240 ring.euclidean_deg(b).is_none()
241 || ring.euclidean_deg(&r).unwrap_or(usize::MAX) < ring.euclidean_deg(b).unwrap()
242 );
243 assert_el_eq!(ring, a, ring.add(ring.mul(q, ring.clone_el(b)), r));
244 }
245 }
246 }
247
248 pub fn test_principal_ideal_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
249 where
250 R::Type: PrincipalIdealRing,
251 {
252 assert!(ring.is_commutative());
253 assert!(ring.is_noetherian());
254 let elements = edge_case_elements.collect::<Vec<_>>();
255
256 let expected_unit = ring.checked_div_min(&ring.zero(), &ring.zero()).unwrap();
257 assert!(
258 ring.is_unit(&expected_unit),
259 "checked_div_min() returned a non-minimal quotient {} * {} = {}",
260 ring.format(&expected_unit),
261 ring.format(&ring.zero()),
262 ring.format(&ring.zero())
263 );
264 let expected_zero = ring.checked_div_min(&ring.zero(), &ring.one()).unwrap();
265 assert!(
266 ring.is_zero(&expected_zero),
267 "checked_div_min() returned a wrong quotient {} * {} = {}",
268 ring.format(&expected_zero),
269 ring.format(&ring.one()),
270 ring.format(&ring.zero())
271 );
272
273 for a in &elements {
274 let expected_unit = ring.checked_div_min(a, a).unwrap();
275 assert!(
276 ring.is_unit(&expected_unit),
277 "checked_div_min() returned a non-minimal quotient {} * {} = {}",
278 ring.format(&expected_unit),
279 ring.format(a),
280 ring.format(a)
281 );
282 }
283
284 for a in &elements {
285 for b in &elements {
286 for c in &elements {
287 let g1 = ring.mul_ref(a, b);
288 let g2 = ring.mul_ref(a, c);
289 let (s, t, g) = ring.extended_ideal_gen(&g1, &g2);
290 assert!(
291 ring.checked_div(&g, a).is_some(),
292 "Wrong ideal generator: ({}) contains the ideal I = ({}, {}), but extended_ideal_gen() found a generator I = ({}) that does not satisfy {} | {}",
293 ring.format(a),
294 ring.format(&g1),
295 ring.format(&g2),
296 ring.format(&g),
297 ring.format(a),
298 ring.format(&g)
299 );
300 assert_el_eq!(ring, g, ring.add(ring.mul_ref(&s, &g1), ring.mul_ref(&t, &g2)));
301 }
302 }
303 }
304 for a in &elements {
305 for b in &elements {
306 let g1 = ring.mul_ref(a, b);
307 let g2 = ring.mul_ref_fst(a, ring.add_ref_fst(b, ring.one()));
308 let (s, t, g) = ring.extended_ideal_gen(&g1, &g2);
309 assert!(
310 ring.checked_div(&g, a).is_some() && ring.checked_div(a, &g).is_some(),
311 "Expected ideals ({}) and I = ({}, {}) to be equal, but extended_ideal_gen() returned generator {} of I",
312 ring.format(a),
313 ring.format(&g1),
314 ring.format(&g2),
315 ring.format(&g)
316 );
317 assert_el_eq!(ring, g, ring.add(ring.mul_ref(&s, &g1), ring.mul_ref(&t, &g2)));
318 }
319 }
320
321 let ZZbig = BigIntRing::RING;
322 let char = ring.characteristic(ZZbig).unwrap();
323 if !ZZbig.is_zero(&char) && ZZbig.is_leq(&char, &ZZbig.power_of_two(30)) {
324 let p = factor(ZZbig, ZZbig.clone_el(&char)).into_iter().next().unwrap().0;
325 let expected = ring.int_hom().map(int_cast(
326 ZZbig.checked_div(&char, &p).unwrap(),
327 StaticRing::<i32>::RING,
328 ZZbig,
329 ));
330 let ann_p = ring.annihilator(&ring.int_hom().map(int_cast(p, StaticRing::<i32>::RING, ZZbig)));
331 assert!(ring.checked_div(&ann_p, &expected).is_some());
332 assert!(ring.checked_div(&expected, &ann_p).is_some());
333 }
334 }
335}