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 Group,
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 Group,
50 ) -> Result<Option<Homomorphism<&'a Group, &'b Group>>, &'static str> {
51 if partial_func.len() != self.gens.len() {
52 return Err("partial func entries should corespond to images for each generator");
53 }
54 for x in partial_func {
55 if !(*x < range_group.size()) {
56 return Err("partial func has invalid element from range group");
57 }
58 }
59
60 let func: Vec<usize> = self
62 .group
63 .elems()
64 .map(|x| {
65 range_group.mul_many(&self.elems[x].iter().map(|g| partial_func[*g]).collect())
66 })
67 .collect();
68
69 for x in self.group.elems() {
72 for g in &self.gens {
73 if func[self.group.mul(x, *g)] != range_group.mul(func[x], func[*g]) {
74 return Ok(None);
75 }
76 }
77 }
78
79 Ok(Some(Homomorphism::new_unchecked(
80 self.group,
81 range_group,
82 func,
83 )))
84 }
85}
86
87impl Group {
88 fn try_find_generating_set(&self, max_size: Option<usize>) -> Result<GeneratingSet, ()> {
89 let mut missing = HashSet::new();
90 for x in self.elems() {
91 missing.insert(x);
92 }
93 missing.remove(&self.ident());
94
95 let mut sg = BTreeSet::new();
96 sg.insert(self.ident());
97 let mut gen_words = vec![vec![]; self.size()];
98 gen_words[self.ident()] = vec![];
99 let mut gens = vec![];
100 while sg.len() < self.size() {
101 match max_size {
103 Some(max_size_val) => {
104 if gens.len() == max_size_val {
105 return Err(());
106 }
107 }
108 None => {}
109 }
110
111 let new_g = *missing.iter().next().unwrap(); gens.push(new_g);
114
115 let mut y;
117 let mut boundary: Vec<usize> = vec![];
118 for s in sg.clone() {
119 y = self.mul(s, new_g);
120 if !sg.contains(&y) {
121 sg.insert(y);
122 missing.remove(&y);
123 gen_words[y] = gen_words[s].clone();
124 gen_words[y].push(gens.len() - 1);
125 boundary.push(y);
126 }
127 }
128 let mut next_boundary: Vec<usize> = vec![];
129 while boundary.len() > 0 {
130 for x in &boundary {
131 for (g_idx, g) in gens.iter().enumerate() {
132 y = self.mul(*x, *g);
133 if !sg.contains(&y) {
134 sg.insert(y);
135 missing.remove(&y);
136 gen_words[y] = gen_words[*x].clone();
137 gen_words[y].push(g_idx);
138 next_boundary.push(y);
139 }
140 }
141 }
142 boundary = next_boundary.clone();
143 next_boundary = vec![];
144 }
145 }
146
147 Ok(GeneratingSet {
148 group: &self,
149 gens: gens,
150 elems: gen_words,
151 })
152 }
153
154 pub fn generating_set(&self) -> GeneratingSet {
155 self.try_find_generating_set(None).unwrap()
156 }
157
158 pub fn small_generating_set(&self, attempts: Option<usize>) -> GeneratingSet {
159 let a = attempts.unwrap_or(12);
160 assert!(a > 0);
161
162 let mut smallest_gens = self.generating_set();
163 for _i in 0..a - 1 {
164 match self.try_find_generating_set(Some(smallest_gens.size() - 1)) {
165 Ok(gens) => {
166 smallest_gens = gens;
167 }
168 Err(_) => {}
169 }
170 }
171
172 return smallest_gens;
173 }
174}
175
176#[cfg(test)]
177mod generating_set_tests {
178 use super::*;
179
180 #[test]
181 fn test_generating_set() {
182 let grp = examples::cyclic_group_structure(10);
183 let g_set = grp.generating_set();
184 g_set.check_state().unwrap();
185
186 let grp = examples::dihedral_group_structure(12);
187 let g_set = grp.generating_set();
188 g_set.check_state().unwrap();
189
190 let grp = examples::symmetric_group_structure(4);
191 let g_set = grp.generating_set();
192 g_set.check_state().unwrap();
193
194 let grp = examples::symmetric_group_structure(5);
195 let g_set = grp.generating_set();
196 g_set.check_state().unwrap();
197 }
198}