1pub trait Magma {
5 type T: Clone;
7
8 fn operate(x: &Self::T, y: &Self::T) -> Self::T;
10
11 fn reverse_operate(x: &Self::T, y: &Self::T) -> Self::T {
12 Self::operate(y, x)
13 }
14
15 fn operate_assign(x: &mut Self::T, y: &Self::T) {
16 *x = Self::operate(x, y);
17 }
18}
19
20pub trait Associative: Magma {
22 #[cfg(test)]
23 fn check_associative(a: &Self::T, b: &Self::T, c: &Self::T) -> bool
24 where
25 Self::T: PartialEq,
26 {
27 ({
28 let ab_c = Self::operate(&Self::operate(a, b), c);
29 let a_bc = Self::operate(a, &Self::operate(b, c));
30 ab_c == a_bc
31 }) && ({
32 let ab_c = Self::reverse_operate(c, &Self::reverse_operate(b, a));
33 let a_bc = Self::reverse_operate(&Self::reverse_operate(c, b), a);
34 ab_c == a_bc
35 }) && ({
36 let mut ab_c = a.clone();
37 Self::operate_assign(&mut ab_c, b);
38 Self::operate_assign(&mut ab_c, c);
39 let mut bc = b.clone();
40 Self::operate_assign(&mut bc, c);
41 let mut a_bc = a.clone();
42 Self::operate_assign(&mut a_bc, &bc);
43 ab_c == a_bc
44 })
45 }
46}
47
48pub trait SemiGroup: Magma + Associative {}
50
51impl<S> SemiGroup for S where S: Magma + Associative {}
52
53pub trait Unital: Magma {
55 fn unit() -> Self::T;
57
58 fn is_unit(x: &Self::T) -> bool
59 where
60 Self::T: PartialEq,
61 {
62 x == &Self::unit()
63 }
64
65 fn set_unit(x: &mut Self::T) {
66 *x = Self::unit();
67 }
68
69 #[cfg(test)]
70 fn check_unital(x: &Self::T) -> bool
71 where
72 Self::T: PartialEq,
73 {
74 let u = Self::unit();
75 let xu = Self::operate(x, &u);
76 let ux = Self::operate(&u, x);
77 let mut any = x.clone();
78 Self::set_unit(&mut any);
79 xu == *x && ux == *x && Self::is_unit(&u) && Self::is_unit(&any)
80 }
81}
82
83pub trait ExpBits {
84 type Iter: Iterator<Item = bool>;
85 fn bits(self) -> Self::Iter;
86}
87
88pub trait SignedExpBits {
89 type T: ExpBits;
90
91 fn neg_and_bits(self) -> (bool, Self::T);
92}
93
94pub struct Bits<T> {
95 n: T,
96}
97
98macro_rules! impl_exp_bits_for_uint {
99 ($($t:ty)*) => {
100 $(
101 impl Iterator for Bits<$t> {
102 type Item = bool;
103 fn next(&mut self) -> Option<bool> {
104 if self.n == 0 {
105 None
106 } else {
107 let bit = (self.n & 1) == 1;
108 self.n >>= 1;
109 Some(bit)
110 }
111 }
112 }
113 impl ExpBits for $t {
114 type Iter = Bits<$t>;
115 fn bits(self) -> Self::Iter {
116 Bits { n: self }
117 }
118 }
119 impl SignedExpBits for $t {
120 type T = $t;
121 fn neg_and_bits(self) -> (bool, Self::T) {
122 (false, self)
123 }
124 }
125 )*
126 };
127}
128impl_exp_bits_for_uint!(u8 u16 u32 u64 u128 usize);
129
130macro_rules! impl_signed_exp_bits_for_sint {
131 ($($s:ty, $u:ty;)*) => {
132 $(
133 impl SignedExpBits for $s {
134 type T = $u;
135 fn neg_and_bits(self) -> (bool, Self::T) {
136 (self < 0, self.unsigned_abs())
137 }
138 }
139 )*
140 };
141}
142impl_signed_exp_bits_for_sint!(i8, u8; i16, u16; i32, u32; i64, u64; i128, u128; isize, usize;);
143
144pub trait Monoid: SemiGroup + Unital {
146 fn pow<E>(mut x: Self::T, exp: E) -> Self::T
148 where
149 E: ExpBits,
150 {
151 let mut res = Self::unit();
152 for bit in exp.bits() {
153 if bit {
154 res = Self::operate(&res, &x);
155 }
156 x = Self::operate(&x, &x);
157 }
158 res
159 }
160
161 fn fold<I>(iter: I) -> Self::T
162 where
163 I: IntoIterator<Item = Self::T>,
164 {
165 let mut iter = iter.into_iter();
166 if let Some(item) = iter.next() {
167 iter.fold(item, |acc, x| Self::operate(&acc, &x))
168 } else {
169 Self::unit()
170 }
171 }
172}
173
174impl<M> Monoid for M where M: SemiGroup + Unital {}
175
176pub trait Invertible: Magma + Unital {
178 fn inverse(x: &Self::T) -> Self::T;
180
181 fn rinv_operate(x: &Self::T, y: &Self::T) -> Self::T {
182 Self::operate(x, &Self::inverse(y))
183 }
184
185 fn rinv_operate_assign(x: &mut Self::T, y: &Self::T) {
186 *x = Self::rinv_operate(x, y);
187 }
188
189 #[cfg(test)]
190 fn check_invertible(x: &Self::T) -> bool
191 where
192 Self::T: PartialEq,
193 {
194 let i = Self::inverse(x);
195 ({
196 let xi = Self::operate(x, &i);
197 let ix = Self::operate(&i, x);
198 Self::is_unit(&xi) && Self::is_unit(&ix)
199 }) && ({
200 let ii = Self::inverse(&i);
201 ii == *x
202 }) && ({
203 let mut xi = x.clone();
204 Self::operate_assign(&mut xi, &i);
205 let mut ix = i.clone();
206 Self::operate_assign(&mut ix, x);
207 Self::is_unit(&xi) && Self::is_unit(&ix)
208 }) && ({
209 let mut xi = x.clone();
210 Self::rinv_operate_assign(&mut xi, x);
211 let mut ix = i.clone();
212 Self::rinv_operate_assign(&mut ix, &i);
213 Self::is_unit(&xi) && Self::is_unit(&ix)
214 })
215 }
216}
217
218pub trait Group: Monoid + Invertible {
220 fn signed_pow<E>(x: Self::T, exp: E) -> Self::T
221 where
222 E: SignedExpBits,
223 {
224 let (neg, exp) = E::neg_and_bits(exp);
225 let res = Self::pow(x, exp);
226 if neg { Self::inverse(&res) } else { res }
227 }
228}
229
230impl<G> Group for G where G: Monoid + Invertible {}
231
232pub trait Commutative: Magma {
234 #[cfg(test)]
235 fn check_commutative(a: &Self::T, b: &Self::T) -> bool
236 where
237 Self::T: PartialEq,
238 {
239 Self::operate(a, b) == Self::operate(b, a)
240 }
241}
242
243pub trait AbelianMonoid: Monoid + Commutative {}
245
246impl<M> AbelianMonoid for M where M: Monoid + Commutative {}
247
248pub trait AbelianGroup: Group + Commutative {}
250
251impl<G> AbelianGroup for G where G: Group + Commutative {}
252
253pub trait Idempotent: Magma {
255 #[cfg(test)]
256 fn check_idempotent(a: &Self::T) -> bool
257 where
258 Self::T: PartialEq,
259 {
260 Self::operate(a, a) == *a
261 }
262}
263
264pub trait IdempotentMonoid: Monoid + Idempotent {}
266
267impl<M> IdempotentMonoid for M where M: Monoid + Idempotent {}
268
269#[macro_export]
270macro_rules! monoid_fold {
271 ($m:ty) => { <$m as Unital>::unit() };
272 ($m:ty,) => { <$m as Unital>::unit() };
273 ($m:ty, $f:expr) => { $f };
274 ($m:ty, $f:expr, $($ff:expr),*) => { <$m as Magma>::operate(&($f), &monoid_fold!($m, $($ff),*)) };
275}
276
277#[macro_export]
278macro_rules! define_monoid {
279 ($Name:ident, $t:ty, |$x:ident, $y:ident| $op:expr, $unit:expr) => {
280 struct $Name;
281 impl Magma for $Name {
282 type T = $t;
283 fn operate($x: &Self::T, $y: &Self::T) -> Self::T {
284 $op
285 }
286 }
287 impl Unital for $Name {
288 fn unit() -> Self::T {
289 $unit
290 }
291 }
292 impl Associative for $Name {}
293 };
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299 use crate::algebra::operations::{AdditiveOperation, MaxOperation};
300
301 #[test]
302 fn test_monoid_pow() {
303 assert_eq!(AdditiveOperation::pow(2, 0u32), 0);
304 assert_eq!(AdditiveOperation::pow(2, 1u32), 2);
305 assert_eq!(AdditiveOperation::pow(2, 3u32), 6);
306 assert_eq!(AdditiveOperation::pow(2, 4usize), 8);
307 }
308
309 #[test]
310 fn test_monoid_fold() {
311 assert_eq!(monoid_fold!(MaxOperation<u32>,), 0);
312 assert_eq!(monoid_fold!(MaxOperation<u32>, 1), 1);
313 assert_eq!(monoid_fold!(MaxOperation<u32>, 1, 2), 2);
314 assert_eq!(monoid_fold!(MaxOperation<u32>, 0, 1, 5, 2), 5);
315 }
316}