1use crate::EucRes;
2extern crate num;
3use num::{ One, Zero, Signed};
4
5pub trait EucExt<T>
6where
7 T: One
8 + Zero
9 + Copy
10 + std::ops::Mul<Output = T>
11 + std::ops::Div<Output = T>
12 + std::ops::Rem<Output = T>
13 + std::ops::Sub<Output = T>
14 + std::cmp::Ord,
15{
16
17 fn euc_ext(mut d1: T, mut d2: T) -> EucRes<T> {
19 let (mut spp, mut sp) = (T::one(), T::zero());
20 let (mut tpp, mut tp) = (T::zero(), T::one());
21 let mut q = d1 / d2;
22
23 loop {
24 (d1, d2) = (d2, d1 % d2);
25 if d2 == T::zero() {
26 break;
27 }
28 (spp, sp, tpp, tp) = (sp, spp - (q * sp), tp, tpp - (q * tp));
29 q = d1 / d2;
30 }
31
32 return EucRes {
33 d: d1,
34 s: sp,
35 t: tp,
36 };
37 }
38}
39
40pub trait Euc<T>
41where
42 T: std::ops::Rem<Output = T> + Zero + std::cmp::Ord + Copy,
43{
44 fn euc(mut d1: T, mut d2: T) -> T {
46 while d2 != T::zero() {
47 (d1, d2) = (d2, d1 % d2);
48 }
49 return d1;
50 }
51
52 fn euc_from_vec(mut d: Vec<T>) -> Result<T, String> {
54 if d.len() == 2 {
55 return Ok(Self::euc(d[0], d[1]));
56 } else if d.len() < 2 {
57 return Err(
58 "critical error occured, length of vector smaller than 2, unable to calculate euc"
59 .to_owned(),
60 );
61 }
62 Ok(Self::euc(
63 d.pop().expect("error occured calculating euc"),
64 match Self::euc_from_vec(d.clone()) {
65 Ok(res) => res,
66 Err(err) => return Err(err),
67 },
68 ))
69 }
70
71 fn euc_recursive(mut d1: T, mut d2: T) -> T {
73 if d1 > d2 {
74 (d1, d2) = (d2, d1)
75 }
76 if d1 % d2 == T::zero() {
77 return d2;
78 } else {
79 Self::euc_recursive(d2, d1 % d2)
80 }
81 }
82}
83
84pub trait Lcm<T>: self::Euc<T> + self::Euc<T>
85where
86 T: std::ops::Mul<Output = T> + std::ops::Rem<Output = T> + Zero + std::cmp::Ord + Copy + Signed,
87{
88
89 fn lcm(d1: T, d2: T) -> T {
91 T::abs(&(d1 * d2)) / Self::euc(d1, d2)
92 }
93
94 fn lcm_recursive(d1: T, d2: T) -> T {
96 T::abs(&(d1 * d2)) / Self::euc_recursive(d1, d2)
97 }
98
99 fn lcm_from_vec(mut d: Vec<T>) -> Result<T, String> {
101 if d.len() == 2 {
102 return Ok(Self::lcm(d[0], d[1]));
103 } else if d.len() < 2 {
104 return Err(
105 "critical error occured, length of vector smaller than 2, unable to calculate lcm"
106 .to_owned(),
107 );
108 }
109 Ok(Self::lcm(
110 d.pop().expect("error occured calculating lcm"),
111 match Self::lcm_from_vec(d.clone()) {
112 Ok(res) => res,
113 Err(err) => return Err(err),
114 },
115 ))
116 }
117}
118
119pub trait Congruence<T>: self::EucExt<T>
120where
121 T: One
122 + Zero
123 + Copy
124 + std::ops::Mul<Output = T>
125 + std::ops::Div<Output = T>
126 + std::ops::Rem<Output = T>
127 + std::ops::Sub<Output = T>
128 + std::cmp::Ord,
129{
130 fn congruence(mut a: T, mut b: T, n: T) -> Result<T, String> {
134 a = a % n;
135 b = b % n;
136 let ecr = Self::euc_ext(a, n);
137
138 if b % ecr.d != T::zero() {
139 return Err("Error occured b%euc_ext(a,n) != 0".to_owned());
140 }
141 let x = (ecr.s * (b / ecr.d)) % n;
142 if x > T::zero() {
143 return Ok(x);
144 }
145 return Ok(x + n);
146 }
147}