1use karpal_core::Monoid;
5
6pub trait Group: Monoid {
11 fn invert(self) -> Self;
12
13 fn combine_inverse(self, other: Self) -> Self
14 where
15 Self: Sized,
16 {
17 self.combine(other.invert())
18 }
19}
20
21macro_rules! impl_signed_group {
22 ($($t:ty),*) => {
23 $(
24 impl Group for $t {
25 fn invert(self) -> Self {
26 -self
27 }
28 }
29 )*
30 };
31}
32
33impl_signed_group!(i8, i16, i32, i64, i128, f32, f64);
34
35impl<A: Group, B: Group> Group for (A, B) {
36 fn invert(self) -> Self {
37 (self.0.invert(), self.1.invert())
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 #[test]
46 fn i32_invert() {
47 assert_eq!(5i32.invert(), -5);
48 assert_eq!((-3i32).invert(), 3);
49 }
50
51 #[test]
52 fn i32_combine_inverse() {
53 assert_eq!(10i32.combine_inverse(3), 7);
54 }
55
56 #[test]
57 fn f64_invert() {
58 assert!((1.5f64.invert() - (-1.5)).abs() < 1e-10);
59 }
60}
61
62#[cfg(test)]
63mod law_tests {
64 use super::*;
65 use karpal_core::Semigroup;
66 use proptest::prelude::*;
67
68 proptest! {
69 #[test]
70 fn left_inverse(a in -100i16..100i16) {
71 prop_assert_eq!(a.invert().combine(a), i16::empty());
72 }
73
74 #[test]
75 fn right_inverse(a in -100i16..100i16) {
76 prop_assert_eq!(a.combine(a.invert()), i16::empty());
77 }
78
79 #[test]
80 fn combine_inverse_is_combine_invert(a in -50i16..50i16, b in -50i16..50i16) {
81 prop_assert_eq!(a.combine_inverse(b), a.combine(b.invert()));
82 }
83 }
84}