algebraeon_groups/
structure.rs1use algebraeon_macros::signature_meta_trait;
2use algebraeon_nzq::traits::Abs;
3use algebraeon_nzq::{Integer, Natural};
4use algebraeon_sets::structure::{MetaType, SetSignature};
5use std::borrow::Borrow;
6use std::collections::{HashMap, HashSet};
7
8#[signature_meta_trait]
10pub trait CompositionSignature: SetSignature {
11 fn compose(&self, a: &Self::Set, b: &Self::Set) -> Self::Set;
12 fn compose_mut(&self, a: &mut Self::Set, b: &Self::Set) {
13 *a = self.compose(a, b);
14 }
15}
16
17#[signature_meta_trait]
19pub trait AssociativeCompositionSignature: CompositionSignature {
20 fn compose_nonempty_list(&self, mut elems: Vec<impl Borrow<Self::Set>>) -> Option<Self::Set> {
22 let mut total = elems.pop()?.borrow().clone();
23 for elem in elems {
24 total = self.compose(&total, elem.borrow());
25 }
26 Some(total)
27 }
28}
29
30#[signature_meta_trait]
32pub trait CommutativeCompositionSignature: CompositionSignature {}
33
34#[signature_meta_trait]
36pub trait LeftCancellativeCompositionSignature: CompositionSignature {
37 fn try_left_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set>;
39}
40
41#[signature_meta_trait]
43pub trait RightCancellativeCompositionSignature: CompositionSignature {
44 fn try_right_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set>;
46}
47
48#[signature_meta_trait]
49pub trait CancellativeCompositionSignature:
50 CommutativeCompositionSignature
51 + LeftCancellativeCompositionSignature
52 + RightCancellativeCompositionSignature
53{
54 fn try_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set>;
55}
56impl<S: CancellativeCompositionSignature> LeftCancellativeCompositionSignature for S {
57 fn try_left_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
58 self.try_difference(a, b)
59 }
60}
61impl<S: CancellativeCompositionSignature> RightCancellativeCompositionSignature for S {
62 fn try_right_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
63 self.try_difference(a, b)
64 }
65}
66
67#[signature_meta_trait]
69pub trait IdentitySignature: SetSignature {
70 fn identity(&self) -> Self::Set;
72}
73
74#[signature_meta_trait]
76pub trait TryLeftInverseSignature: IdentitySignature + CompositionSignature {
77 fn try_left_inverse(&self, a: &Self::Set) -> Option<Self::Set>;
79}
80
81#[signature_meta_trait]
83pub trait TryRightInverseSignature: IdentitySignature + CompositionSignature {
84 fn try_right_inverse(&self, a: &Self::Set) -> Option<Self::Set>;
86}
87
88#[signature_meta_trait]
90pub trait TryInverseSignature: IdentitySignature + CompositionSignature {
91 fn try_inverse(&self, a: &Self::Set) -> Option<Self::Set>;
96}
97
98impl<S: TryInverseSignature + CommutativeCompositionSignature> TryLeftInverseSignature for S {
99 fn try_left_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
100 self.try_inverse(a)
101 }
102}
103
104impl<S: TryInverseSignature + CommutativeCompositionSignature> TryRightInverseSignature for S {
105 fn try_right_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
106 self.try_inverse(a)
107 }
108}
109
110#[signature_meta_trait]
112pub trait MonoidSignature: IdentitySignature + AssociativeCompositionSignature {
113 fn compose_list(&self, elems: Vec<impl Borrow<Self::Set>>) -> Self::Set {
114 if elems.is_empty() {
115 self.identity()
116 } else {
117 self.compose_nonempty_list(elems).unwrap()
118 }
119 }
120
121 fn nat_pow(&self, a: &Self::Set, n: &Natural) -> Self::Set {
122 if *n == Natural::ZERO {
123 self.identity()
124 } else if *n == Natural::ONE {
125 a.clone()
126 } else {
127 debug_assert!(*n >= Natural::TWO);
128 let bits: Vec<_> = n.bits().collect();
129 let mut pows = vec![a.clone()];
130 while pows.len() < bits.len() {
131 pows.push(self.compose(pows.last().unwrap(), pows.last().unwrap()));
132 }
133 let count = bits.len();
134 debug_assert_eq!(count, pows.len());
135 let mut ans = self.identity();
136 for i in 0..count {
137 if bits[i] {
138 ans = self.compose(&ans, &pows[i]);
139 }
140 }
141 ans
142 }
143 }
144}
145
146#[signature_meta_trait]
148pub trait GroupSignature:
149 MonoidSignature
150 + TryInverseSignature
151 + TryLeftInverseSignature
152 + TryRightInverseSignature
153 + LeftCancellativeCompositionSignature
154 + RightCancellativeCompositionSignature
155{
156 fn inverse(&self, a: &Self::Set) -> Self::Set;
157
158 fn int_pow(&self, a: &Self::Set, n: &Integer) -> Self::Set {
159 #[allow(clippy::comparison_chain)]
160 if *n == Integer::ZERO {
161 self.identity()
162 } else if *n > Integer::ZERO {
163 self.nat_pow(a, &n.abs())
164 } else {
165 self.nat_pow(&self.inverse(a), &n.abs())
166 }
167 }
168
169 fn generated_finite_subgroup_table(
170 &self,
171 generators: Vec<Self::Set>,
172 ) -> (
173 crate::composition_table::group::FiniteGroupMultiplicationTable,
174 Vec<Self::Set>,
175 HashMap<Self::Set, usize>,
176 )
177 where
178 Self::Set: std::hash::Hash + Eq,
179 {
180 let mut n = 0;
181 let mut idx_to_elem: Vec<Self::Set> = vec![];
182 let mut elem_to_idx: HashMap<Self::Set, usize> = HashMap::new();
183 let mut mul: Vec<Vec<Option<usize>>> = vec![];
184 let mut to_mul: Vec<(usize, usize)> = vec![];
185
186 macro_rules! add_elem {
187 ($elem : expr) => {{
188 debug_assert_eq!(idx_to_elem.len(), n);
189 debug_assert_eq!(elem_to_idx.len(), n);
190 debug_assert_eq!(mul.len(), n);
191 for m in &mul {
192 debug_assert_eq!(m.len(), n);
193 }
194 if !elem_to_idx.contains_key(&$elem) {
195 n += 1;
196 let k = elem_to_idx.len();
197 idx_to_elem.push($elem.clone());
198 elem_to_idx.insert($elem, k);
199 for i in (0..k) {
200 mul[i].push(None);
201 to_mul.push((i, k));
202 to_mul.push((k, i));
203 }
204 mul.push(vec![None; k + 1]);
205 to_mul.push((k, k));
206 k
207 } else {
208 *elem_to_idx.get(&$elem).unwrap()
209 }
210 }};
211 }
212
213 add_elem!(self.identity());
214 for g in generators {
215 add_elem!(g);
216 }
217 #[allow(clippy::manual_while_let_some)]
218 while !to_mul.is_empty() {
219 let (i, j) = to_mul.pop().unwrap();
220 let k = add_elem!(self.compose(&idx_to_elem[i], &idx_to_elem[j]));
221 debug_assert!(mul[i][j].is_none());
222 mul[i][j] = Some(k);
223 }
224 drop(to_mul);
225 let mul = mul
226 .into_iter()
227 .map(|m| m.into_iter().map(|x| x.unwrap()).collect::<Vec<_>>())
228 .collect::<Vec<_>>();
229 let inv = idx_to_elem
230 .iter()
231 .map(|elem| *elem_to_idx.get(&self.inverse(elem)).unwrap())
232 .collect::<Vec<_>>();
233
234 let grp = crate::composition_table::group::FiniteGroupMultiplicationTable::new_unchecked(
235 n, 0, inv, mul, None, None,
236 );
237
238 #[cfg(debug_assertions)]
239 grp.check_state().unwrap();
240
241 (grp, idx_to_elem, elem_to_idx)
242 }
243
244 fn generated_finite_subgroup(&self, gens: Vec<Self::Set>) -> FiniteSubgroup<Self::Set>
245 where
246 Self::Set: std::hash::Hash + Eq,
247 {
248 let mut sg = HashSet::new();
250 sg.insert(self.identity());
251
252 let mut boundary = vec![self.identity()];
253 let mut next_boundary = vec![];
254 let mut y;
255 while !boundary.is_empty() {
256 println!("{}", sg.len());
257 for x in &boundary {
258 for g in &gens {
259 y = self.compose(x, g);
260 if !sg.contains(&y) {
261 sg.insert(y.clone());
262 next_boundary.push(y);
263 }
264 }
265 }
266 boundary = next_boundary.clone();
267 next_boundary = vec![];
268 }
269
270 FiniteSubgroup {
271 elems: sg.into_iter().collect(),
272 }
273 }
274}
275
276#[signature_meta_trait]
277pub trait AbelianGroupSignature:
278 GroupSignature + CommutativeCompositionSignature + CancellativeCompositionSignature
279{
280}
281impl<S: GroupSignature + CommutativeCompositionSignature + CancellativeCompositionSignature>
282 AbelianGroupSignature for S
283{
284}
285
286#[derive(Debug, Clone)]
287pub struct FiniteSubgroup<Set> {
288 elems: Vec<Set>,
289}
290
291impl<Set> FiniteSubgroup<Set> {
292 pub fn size(&self) -> usize {
293 self.elems.len()
294 }
295
296 pub fn elements(&self) -> impl Iterator<Item = &Set> {
297 self.elems.iter()
298 }
299}