1use crate::flag::Flag;
4use crate::iterators::*;
5use sprs::{CsMat, TriMatI, CSC, CSR};
6
7fn induce_and_reduce<F: Flag>(type_size: usize, f: &F, subset: &[usize]) -> F {
8 f.induce(subset).canonical_typed(type_size)
9}
10
11pub fn count_subflag_tabulate<F: Flag>(type_size: usize, f_vec: &[F], g_vec: &[F]) -> CsMat<u32> {
19 let k = f_vec[0].size();
20 let n = g_vec[0].size();
21 assert!(type_size <= k && k <= n);
22 let mut res = CsMat::empty(CSR, f_vec.len());
24 for g in g_vec {
25 let mut column = vec![0; f_vec.len()];
26 let mut iter = Choose::with_fixed_part(n, k, type_size);
28 while let Some(subset) = iter.next() {
29 let f0 = induce_and_reduce(type_size, g, subset);
30 match f_vec.binary_search(&f0) {
31 Ok(i) => column[i] += 1,
32 Err(_) => {
33 assert!(!F::HEREDITARY, "Flag not found: {:?}", &f0);
34 }
35 };
36 }
37 res = res.append_outer(&column)
38 }
39 res
40}
41
42pub fn count_split_tabulate<F: Flag>(
55 type_size: usize,
56 f1_vec: &[F],
57 f2_vec: &[F],
58 g_vec: &[F],
59) -> Vec<CsMat<u32>> {
60 let k1 = f1_vec[0].size();
61 let k2 = f2_vec[0].size();
62 let n = g_vec[0].size();
63 assert!(type_size <= k1 && k1 <= n);
64 assert_eq!(n, k1 + k2 - type_size);
65 let shape = (f1_vec.len(), f2_vec.len());
67 let storage = if shape.0 < shape.1 { CSR } else { CSC };
68 let mut res: Vec<CsMat<u32>> = Vec::with_capacity(g_vec.len());
70
71 for g in g_vec {
72 let mut tri_mat = TriMatI::new(shape); let mut iter = Split::with_fixed_part(n, k1, type_size);
74 while let Some((subset1, subset2)) = iter.next() {
75 let f1 = induce_and_reduce(type_size, g, subset1);
76 let f2 = induce_and_reduce(type_size, g, subset2);
77 if let (Ok(i1), Ok(i2)) = (f1_vec.binary_search(&f1), f2_vec.binary_search(&f2)) {
78 tri_mat.add_triplet(i1, i2, 1);
79 } else if F::HEREDITARY {
80 panic!("Flag not found")
81 };
82 }
83 let mat = if storage == CSR {
84 tri_mat.to_csr()
85 } else {
86 tri_mat.to_csc()
87 };
88 res.push(mat)
89 }
90 res
91}
92
93pub fn unlabeling_tabulate<F: Flag>(
98 eta: &[usize],
99 input_vec: &[F],
100 output_vec: &[F],
101) -> Vec<usize> {
102 let type_size = eta.len();
103 let mut res = Vec::new();
104 for flag in input_vec {
105 let unlabeled = flag.select_type(eta).canonical_typed(type_size);
106 if type_size == 0 {
108 debug_assert_eq!(unlabeled, unlabeled.canonical_typed(0));
109 debug_assert_eq!(unlabeled, unlabeled.canonical());
110 }
111 res.push(
112 output_vec.binary_search(&unlabeled).unwrap_or_else(|_| {
113 panic!("Flag not found (type {}): {:?}", type_size, &unlabeled)
114 }),
115 )
116 }
117 res
118}
119
120pub fn unlabeling_count_tabulate<F: Flag>(
147 eta: &[usize],
148 type_size: usize,
149 input_vec: &[F],
150) -> Vec<u32> {
151 assert!(!input_vec.is_empty());
153 let mut res = vec![0; input_vec.len()];
154 for (i, flag) in input_vec.iter().enumerate() {
155 let flag2 = flag.select_type(eta).canonical_typed(eta.len());
156 let aut_typed = flag.stabilizer(type_size).count() as u32;
157 let aut = flag2.stabilizer(eta.len()).count() as u32;
158 assert_eq!(aut % aut_typed, 0);
159 res[i] = aut / aut_typed;
160 }
161 res
162}
163
164pub fn invariant_classes<F: Flag>(eta: &[usize], type_size: usize, input_vec: &[F]) -> Vec<usize> {
172 assert!(!input_vec.is_empty());
175 let n = input_vec[0].size();
176 assert!(type_size <= n);
177 if !eta.is_empty() {
178 unimplemented!()
179 };
180 let type_set: Vec<_> = (0..type_size).collect();
181 let type_flag = input_vec[0].induce(&type_set).canonical_typed(eta.len());
182 let type_automorphisms: Vec<_> = type_flag
184 .stabilizer(eta.len())
185 .map(|mut f| {
186 f.extend(type_size..n);
187 f
188 })
189 .collect();
190 let mut class = vec![None; input_vec.len()];
192 let mut n_classes = 0;
193 for (i, flag) in input_vec.iter().enumerate() {
194 if class[i].is_none() {
195 let new_class = n_classes;
196 n_classes += 1;
197 for phi in &type_automorphisms {
198 let flag2 = flag.apply_morphism(phi).canonical_typed(type_size);
199 let id = input_vec.binary_search(&flag2).expect("Flag not found");
200 match class[id] {
201 Some(class_id) => assert_eq!(class_id, new_class),
202 None => class[id] = Some(new_class),
203 }
204 }
205 }
206 }
207 class.into_iter().map(|c| c.unwrap()).collect()
208}
209
210pub fn class_matrices(class: &[usize]) -> (CsMat<i64>, CsMat<i64>) {
212 assert!(!class.is_empty());
213 let n_classes = *class.iter().max().unwrap() + 1;
214 let n_flags = class.len();
215 let mut invariant = TriMatI::new((n_flags, n_classes));
216 let mut antiinvariant = TriMatI::new((n_flags, n_flags - n_classes));
217 let mut first_of_class = Vec::new();
220 for (i, &c) in class.iter().enumerate() {
221 invariant.add_triplet(i, c, 1);
223 if c < first_of_class.len() {
225 let col = i - first_of_class.len();
226 antiinvariant.add_triplet(i, col, 1);
227 antiinvariant.add_triplet(first_of_class[c], col, -1);
228 } else {
229 assert_eq!(c, first_of_class.len());
230 first_of_class.push(i)
231 }
232 }
233 (invariant.to_csc(), antiinvariant.to_csc())
234}
235
236#[cfg(test)]
238mod tests {
239 use super::*;
240 use crate::flags::*;
241 use canonical_form::Canonize;
242
243 fn count_subflags<F: Flag>(type_size: usize, f: &F, g: &F) -> u32 {
246 assert_eq!(*f, f.canonical_typed(type_size));
248 let k = f.size();
249 let n = g.size();
250 assert!(type_size <= k && k <= n);
251 let mut count = 0;
252 let mut iter = Choose::with_fixed_part(n, k, type_size);
253 while let Some(subset) = iter.next() {
254 if induce_and_reduce(type_size, g, subset) == *f {
255 count += 1;
256 }
257 }
258 count
259 }
260
261 fn count_split<F: Flag>(type_size: usize, f1: &F, f2: &F, g: &F) -> u32 {
265 assert_eq!(*f1, f1.canonical_typed(type_size));
266 assert_eq!(*f2, f2.canonical_typed(type_size));
267 let k1 = f1.size();
268 let k2 = f2.size();
269 let n = g.size();
270 assert!(type_size <= k1 && k1 <= n);
271 assert_eq!(n, k1 + k2 - type_size);
272 let mut count = 0;
273 let mut iter = Split::with_fixed_part(n, k1, type_size);
274 while let Some((subset1, subset2)) = iter.next() {
275 if *f1 == induce_and_reduce(type_size, g, subset1)
276 && *f2 == induce_and_reduce(type_size, g, subset2)
277 {
278 count += 1;
279 }
280 }
281 count
282 }
283
284 fn count_subflags_ext<F: Flag>(sigma: usize, h: &F, g: &F) -> u32 {
285 count_subflags(sigma, &h.canonical_typed(sigma), g)
286 }
287
288 #[test]
289 fn unit_count_subflags() {
290 let cherry = Graph::new(3, &[(0, 1), (1, 2)]);
291 let c4 = Graph::cycle(4);
292 assert_eq!(4, count_subflags_ext(0, &cherry, &c4));
293 assert_eq!(2, count_subflags_ext(1, &cherry, &c4));
294
295 let c5 = Graph::cycle(5);
296 assert_eq!(
297 12,
298 count_subflags(0, &c5.canonical(), &Graph::petersen().canonical())
299 );
300 }
301
302 #[test]
303 fn count_subflags_typed() {
304 let p3 = Graph::new(3, &[(0, 1), (1, 2)]);
305 let p4 = Graph::new(4, &[(0, 1), (1, 2), (2, 3)]);
306 let g = Graph::new(6, &[(2, 0), (0, 5), (2, 5), (0, 4), (4, 3)]);
307 let g2 = Graph::new(
308 7,
309 &[
310 (0, 1),
311 (0, 5),
312 (1, 2),
313 (1, 4),
314 (2, 3),
315 (2, 4),
316 (5, 4),
317 (2, 5),
318 ],
319 );
320 let g3 = Graph::new(5, &[(0, 1), (1, 2), (1, 4), (2, 4), (2, 3)]);
321
322 assert_eq!(1, count_subflags_ext(1, &p3, &g));
323 assert_eq!(1, count_subflags_ext(3, &p4, &g2));
324 assert_eq!(1, count_subflags_ext(2, &g3, &g2));
325 }
326
327 #[test]
328 fn unit_count_split() {
329 let cherry = Graph::new(3, &[(0, 1), (1, 2)]).canonical();
330 let edge = Graph::new(2, &[(0, 1)]).canonical();
331 let g = Graph::new(5, &[(0, 1), (1, 2), (2, 3), (3, 4), (4, 0), (0, 2)]).canonical();
332 assert_eq!(4, count_split(0, &cherry, &edge, &g));
333 }
334
335 fn csm_get<N: num::Zero + Copy>(mat: &CsMat<N>, i: usize, j: usize) -> N {
336 assert!(i < mat.rows() && j < mat.cols());
337 *mat.get(i, j).unwrap_or(&N::zero())
338 }
339
340 fn count_subflag_consistency<F: Flag>(k: usize, n: usize) {
341 let a = F::generate(k);
342 let b = F::generate(n);
343 let tab = count_subflag_tabulate(0, &a, &b);
344 for (i, ai) in a.iter().enumerate() {
345 for (j, bj) in b.iter().enumerate() {
346 assert_eq!(count_subflags(0, ai, bj), csm_get(&tab, j, i))
347 }
348 }
349 }
350
351 fn count_split_consistency<F: Flag>(k: usize, n: usize) {
352 let left = F::generate(k);
353 let right = F::generate(n - k);
354 let prod = F::generate(n);
355 let tab = count_split_tabulate(0, &left, &right, &prod);
356 for (i, left_flag) in left.iter().enumerate() {
357 for (j, right_flag) in right.iter().enumerate() {
358 for (p, prod_flag) in prod.iter().enumerate() {
359 assert_eq!(
360 count_split(0, left_flag, right_flag, prod_flag),
361 csm_get(&tab[p], i, j)
362 )
363 }
364 }
365 }
366 }
367
368 #[test]
369 fn unit_count_subflag_tabulate() {
370 count_subflag_consistency::<Graph>(3, 5);
371 }
372
373 #[test]
374 fn unit_count_split_tabulate() {
375 count_split_consistency::<Graph>(2, 5);
376 }
377}