yui_core/abst/
euc_ring.rs1use std::ops::{Div, DivAssign, Rem, RemAssign};
4use crate::{Ring, RingOps};
5
6pub trait EucRingOps<T = Self>:
7 RingOps<T> +
8 Div<T, Output = T> +
9 for<'a> Div<&'a T, Output = T> +
10 Rem<T, Output = T> +
11 for<'a> Rem<&'a T, Output = T> +
12{}
13
14pub trait EucRing:
15 Ring +
16 EucRingOps +
17 DivAssign +
18 for<'a> DivAssign<&'a Self> +
19 RemAssign +
20 for<'a> RemAssign<&'a Self>
21where
22 for<'a> &'a Self: EucRingOps<Self>,
23{
24 fn divides(&self, y: &Self) -> bool {
25 !self.is_zero() && (y % self).is_zero()
26 }
27
28 fn gcd(x: &Self, y: &Self) -> Self {
29 if x.is_zero() && y.is_zero() { return Self::zero() }
30 if x.divides(y) { return x.clone() }
31 if y.divides(x) { return y.clone() }
32
33 let (mut x, mut y) = (x.clone(), y.clone());
34
35 while !y.is_zero() {
36 let r = &x % &y;
37 (x, y) = (y, r);
38 }
39
40 x.into_normalized()
41 }
42
43 fn gcdx(x: &Self, y: &Self) -> (Self, Self, Self) {
44 if x.is_zero() && y.is_zero() { return (Self::zero(), Self::zero(), Self::zero()) }
45 if x.divides(y) { return (x.clone(), Self::one(), Self::zero()) }
46 if y.divides(x) { return (y.clone(), Self::zero(), Self::one()) }
47
48 let (mut x, mut y) = (x.clone(), y.clone());
49 let (mut s0, mut s1) = (Self::one(), Self::zero());
50 let (mut t0, mut t1) = (Self::zero(), Self::one() );
51
52 while !y.is_zero() {
53 let q = &x / &y;
54 let r = &x % &y;
55
56 (x, y) = (y, r);
57 (s1, s0) = (s0 - &q * &s1, s1);
58 (t1, t0) = (t0 - &q * &t1, t1);
59 }
60
61 let (d, s, t) = (x, s0, t0);
62
63 let u = d.normalizing_unit();
64 match u.is_one() {
65 true => (d, s, t),
66 false => (d * &u, s * &u, t * &u)
67 }
68 }
69
70 fn lcm(x: &Self, y: &Self) -> Self {
71 let g = Self::gcd(x, y);
72 let m = x * (y / g);
73 m.into_normalized()
74 }
75}