algebraeon_groups/composition_table/
subset.rs1use super::group::*;
2use super::normal_subgroup::*;
3use super::subgroup::*;
4use std::collections::HashSet;
5
6pub struct Subset<'a> {
7 group: &'a FiniteGroupMultiplicationTable,
8 elems: HashSet<usize>,
9}
10
11impl<'a> Subset<'a> {
12 pub fn check_state(&self) -> Result<(), &'static str> {
13 for x in &self.elems {
14 if !(*x < self.group.size()) {
15 return Err("invalid subset element");
16 }
17 }
18
19 Ok(())
20 }
21
22 pub fn new_unchecked(group: &'a FiniteGroupMultiplicationTable, elems: HashSet<usize>) -> Self {
23 Self { group, elems }
24 }
25
26 pub fn group(&self) -> &FiniteGroupMultiplicationTable {
27 &self.group
28 }
29
30 pub fn elems(&self) -> &HashSet<usize> {
31 &self.elems
32 }
33
34 pub fn size(&self) -> usize {
35 self.elems.len()
36 }
37
38 pub fn add_elem(&mut self, x: usize) -> Result<(), ()> {
39 if self.elems.contains(&x) {
40 return Ok(());
41 } else if !(x < self.group.size()) {
42 return Err(());
43 }
44 self.elems.insert(x);
45 Ok(())
46 }
47
48 pub fn left_mul(&self, g: usize) -> Result<Subset, ()> {
49 if !(g < self.group.size()) {
50 return Err(());
51 }
52 Ok(Subset {
53 group: self.group,
54 elems: self.elems.iter().map(|h| self.group.mul(g, *h)).collect(),
55 })
56 }
57
58 pub fn right_mul(&self, g: usize) -> Result<Subset, ()> {
59 if !(g < self.group.size()) {
60 return Err(());
61 }
62 Ok(Subset {
63 group: self.group,
64 elems: self.elems.iter().map(|h| self.group.mul(*h, g)).collect(),
65 })
66 }
67
68 pub fn is_subgroup(&self) -> bool {
69 for x in &self.elems {
70 for y in &self.elems {
71 if !self.elems.contains(&self.group.mul(*x, *y)) {
72 return false;
73 }
74 }
75 }
76 true
77 }
78
79 pub fn to_subgroup(&self) -> Option<Subgroup> {
80 match self.is_subgroup() {
81 true => Some(Subgroup {
82 subset: self.clone(),
83 }),
84 false => None,
85 }
86 }
87
88 pub fn generated_subgroup(&self) -> Result<Subgroup<'a>, ()> {
89 for g in &self.elems {
90 if !(*g < self.group.size()) {
91 return Err(());
92 }
93 }
94
95 let mut sg = HashSet::new();
97 sg.insert(self.group.ident());
98
99 let mut boundary = vec![self.group.ident()];
100 let mut next_boundary = vec![];
101 let mut y;
102 while boundary.len() > 0 {
103 for x in &boundary {
104 for g in &self.elems {
105 y = self.group.mul(*x, *g);
106 if !sg.contains(&y) {
107 sg.insert(y);
108 next_boundary.push(y);
109 }
110 }
111 }
112 boundary = next_boundary.clone();
113 next_boundary = vec![];
114 }
115 Ok(Subgroup {
116 subset: Subset {
117 group: self.group,
118 elems: sg,
119 },
120 })
121 }
122
123 pub fn normal_closure(&self) -> Result<NormalSubgroup<'a>, &'static str> {
124 for g in &self.elems {
125 if !(*g < self.group.size()) {
126 return Err("gen out of range");
127 }
128 }
129
130 let conj_info = self.group.conjugacy_classes().partition;
131
132 let mut sg = HashSet::new();
134 sg.insert(self.group.ident());
135
136 let mut boundary = vec![self.group.ident()];
137 let mut next_boundary = vec![];
138 while boundary.len() > 0 {
139 for x in &boundary {
140 for g in &self.elems {
141 for y in conj_info.class_containing(self.group.mul(*x, *g)) {
142 if !sg.contains(y) {
143 sg.insert(*y);
144 next_boundary.push(*y);
145 }
146 }
147 }
148 }
149 boundary = next_boundary.clone();
150 next_boundary = vec![];
151 }
152 Ok(NormalSubgroup::new_unchecked(Subgroup {
153 subset: Subset {
154 group: self.group,
155 elems: sg,
156 },
157 }))
158 }
159}
160
161impl<'a> IntoIterator for Subset<'a> {
162 type Item = usize;
163 type IntoIter = <HashSet<usize> as IntoIterator>::IntoIter;
164
165 fn into_iter(self) -> Self::IntoIter {
166 self.elems.into_iter()
167 }
168}
169
170impl<'a> PartialEq for Subset<'a> {
171 fn eq(&self, other: &Self) -> bool {
172 self.elems == other.elems
173 }
174}
175
176impl<'a> Eq for Subset<'a> {}
177
178impl<'a> Clone for Subset<'a> {
185 fn clone(&self) -> Self {
186 Self {
187 group: self.group,
188 elems: self.elems.clone(),
189 }
190 }
191}
192
193#[cfg(test)]
194mod subset_tests {
195 use super::*;
196
197 #[test]
198 fn subset_left_mul() {
199 use crate::examples::symmetric::Permutation;
200
201 let (grp, _perms, elems) = Permutation::<4>::symmetric_composition_table();
202
203 let subset = Subset {
204 group: &grp,
205 elems: vec![
206 elems[&Permutation::new([1, 2, 3, 0]).unwrap()],
207 elems[&Permutation::new([0, 1, 3, 2]).unwrap()],
208 elems[&Permutation::new([3, 2, 1, 0]).unwrap()],
209 ]
210 .into_iter()
211 .collect(),
212 };
213 let left_mul_subset = subset
214 .left_mul(elems[&Permutation::new([1, 2, 0, 3]).unwrap()])
215 .unwrap();
216 assert_eq!(
217 left_mul_subset.elems,
218 Subset {
219 group: &grp,
220 elems: vec![
221 elems[&Permutation::new([2, 0, 3, 1]).unwrap()],
222 elems[&Permutation::new([1, 2, 3, 0]).unwrap()],
223 elems[&Permutation::new([3, 0, 2, 1]).unwrap()]
224 ]
225 .into_iter()
226 .collect()
227 }
228 .elems
229 );
230 }
231
232 #[test]
233 fn subset_right_mul() {
234 use crate::examples::symmetric::Permutation;
235
236 let (grp, _perms, elems) = Permutation::<4>::symmetric_composition_table();
237
238 let subset = Subset {
239 group: &grp,
240 elems: vec![
241 elems[&Permutation::new([1, 2, 3, 0]).unwrap()],
242 elems[&Permutation::new([0, 1, 3, 2]).unwrap()],
243 elems[&Permutation::new([3, 2, 1, 0]).unwrap()],
244 ]
245 .into_iter()
246 .collect(),
247 };
248 let left_mul_subset = subset
249 .right_mul(elems[&Permutation::new([1, 2, 0, 3]).unwrap()])
250 .unwrap();
251 assert_eq!(
252 left_mul_subset.elems,
253 Subset {
254 group: &grp,
255 elems: vec![
256 elems[&Permutation::new([2, 3, 1, 0]).unwrap()],
257 elems[&Permutation::new([1, 3, 0, 2]).unwrap()],
258 elems[&Permutation::new([2, 1, 3, 0]).unwrap()]
259 ]
260 .into_iter()
261 .collect()
262 }
263 .elems
264 );
265 }
266}