algebraeon_groups/composition_table/
generating_set.rs1use std::collections::{BTreeSet, HashSet};
2
3use super::group::*;
4use super::homomorphism::*;
5
6pub struct GeneratingSet<'a> {
7 group: &'a FiniteGroupMultiplicationTable,
8 gens: Vec<usize>, elems: Vec<Vec<usize>>, }
11
12impl<'a> GeneratingSet<'a> {
13 pub fn check_state(&self) -> Result<(), &'static str> {
14 for g in &self.gens {
15 if !(*g < self.group.size()) {
16 return Err("bad generator");
17 }
18 }
19
20 if self.elems.len() != self.group.size() {
21 return Err("bad elems len");
22 }
23
24 for x in self.group.elems() {
25 if x != self.group.mul_many(
26 &self.elems[x]
27 .iter()
28 .map(|gen_idx| self.gens[*gen_idx])
29 .collect(),
30 ) {
31 return Err("incorrect word of gens for elem");
32 }
33 }
34
35 Ok(())
36 }
37
38 pub fn size(&self) -> usize {
39 self.gens.len()
40 }
41
42 pub fn gens(&self) -> &Vec<usize> {
43 &self.gens
44 }
45
46 pub fn generated_homomorphism<'b>(
47 &self,
48 partial_func: &Vec<usize>,
49 range_group: &'b FiniteGroupMultiplicationTable,
50 ) -> Result<
51 Option<
52 Homomorphism<&'a FiniteGroupMultiplicationTable, &'b FiniteGroupMultiplicationTable>,
53 >,
54 &'static str,
55 > {
56 if partial_func.len() != self.gens.len() {
57 return Err("partial func entries should corespond to images for each generator");
58 }
59 for x in partial_func {
60 if !(*x < range_group.size()) {
61 return Err("partial func has invalid element from range group");
62 }
63 }
64
65 let func: Vec<usize> = self
67 .group
68 .elems()
69 .map(|x| {
70 range_group.mul_many(&self.elems[x].iter().map(|g| partial_func[*g]).collect())
71 })
72 .collect();
73
74 for x in self.group.elems() {
77 for g in &self.gens {
78 if func[self.group.mul(x, *g)] != range_group.mul(func[x], func[*g]) {
79 return Ok(None);
80 }
81 }
82 }
83
84 Ok(Some(Homomorphism::new_unchecked(
85 self.group,
86 range_group,
87 func,
88 )))
89 }
90}
91
92impl FiniteGroupMultiplicationTable {
93 fn try_find_generating_set(&self, max_size: Option<usize>) -> Result<GeneratingSet, ()> {
94 let mut missing = HashSet::new();
95 for x in self.elems() {
96 missing.insert(x);
97 }
98 missing.remove(&self.ident());
99
100 let mut sg = BTreeSet::new();
101 sg.insert(self.ident());
102 let mut gen_words = vec![vec![]; self.size()];
103 gen_words[self.ident()] = vec![];
104 let mut gens = vec![];
105 while sg.len() < self.size() {
106 match max_size {
108 Some(max_size_val) => {
109 if gens.len() == max_size_val {
110 return Err(());
111 }
112 }
113 None => {}
114 }
115
116 let new_g = *missing.iter().next().unwrap(); gens.push(new_g);
119
120 let mut y;
122 let mut boundary: Vec<usize> = vec![];
123 for s in sg.clone() {
124 y = self.mul(s, new_g);
125 if !sg.contains(&y) {
126 sg.insert(y);
127 missing.remove(&y);
128 gen_words[y] = gen_words[s].clone();
129 gen_words[y].push(gens.len() - 1);
130 boundary.push(y);
131 }
132 }
133 let mut next_boundary: Vec<usize> = vec![];
134 while boundary.len() > 0 {
135 for x in &boundary {
136 for (g_idx, g) in gens.iter().enumerate() {
137 y = self.mul(*x, *g);
138 if !sg.contains(&y) {
139 sg.insert(y);
140 missing.remove(&y);
141 gen_words[y] = gen_words[*x].clone();
142 gen_words[y].push(g_idx);
143 next_boundary.push(y);
144 }
145 }
146 }
147 boundary = next_boundary.clone();
148 next_boundary = vec![];
149 }
150 }
151
152 Ok(GeneratingSet {
153 group: &self,
154 gens: gens,
155 elems: gen_words,
156 })
157 }
158
159 pub fn generating_set(&self) -> GeneratingSet {
160 self.try_find_generating_set(None).unwrap()
161 }
162
163 pub fn small_generating_set(&self, attempts: Option<usize>) -> GeneratingSet {
164 let a = attempts.unwrap_or(12);
165 assert!(a > 0);
166
167 let mut smallest_gens = self.generating_set();
168 for _i in 0..a - 1 {
169 match self.try_find_generating_set(Some(smallest_gens.size() - 1)) {
170 Ok(gens) => {
171 smallest_gens = gens;
172 }
173 Err(_) => {}
174 }
175 }
176
177 return smallest_gens;
178 }
179}
180
181#[cfg(test)]
182mod generating_set_tests {
183 use super::*;
184
185 #[test]
186 fn test_generating_set() {
187 let grp = examples::cyclic_group_structure(10);
188 let g_set = grp.generating_set();
189 g_set.check_state().unwrap();
190
191 let grp = examples::dihedral_group_structure(12);
192 let g_set = grp.generating_set();
193 g_set.check_state().unwrap();
194
195 let grp = examples::symmetric_group_structure(4);
196 let g_set = grp.generating_set();
197 g_set.check_state().unwrap();
198
199 let grp = examples::symmetric_group_structure(5);
200 let g_set = grp.generating_set();
201 g_set.check_state().unwrap();
202 }
203}