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