1use std::collections::BTreeMap;
8
9mod coloring;
10pub mod set;
11mod tree;
12
13pub use coloring::{Coloring, ReversibleColoring};
14pub use set::Map;
15pub use set::Set;
16
17pub trait Normalize: Sized {
19 type Elements: Set;
21
22 type Color: Ord;
24
25 type Cache;
29
30 type Morphed: Ord;
31
32 fn initialize_cache(&self) -> Self::Cache;
37
38 fn elements(&self) -> &Self::Elements;
40
41 fn initial_coloring(&self) -> <Self::Elements as Set>::Map<Self::Color>;
43
44 fn refine_coloring(
46 &self,
47 _cache: &mut Self::Cache,
48 _coloring: &mut ReversibleColoring<Self::Elements>,
49 ) {
50 }
52
53 fn apply_morphism<F>(&self, morphism: F) -> Self::Morphed
55 where
56 F: Fn(&<Self::Elements as Set>::Item) -> usize;
57
58 fn normal_form(&self) -> Self::Morphed
60 where
61 <Self::Elements as Set>::Map<usize>: Clone,
62 {
63 self.normalize().0
64 }
65
66 fn canonical_permutation(&self) -> <Self::Elements as Set>::Map<usize>
68 where
69 <Self::Elements as Set>::Map<usize>: Clone,
70 {
71 self.normalize().1
72 }
73
74 fn normalize(&self) -> (Self::Morphed, <Self::Elements as Set>::Map<usize>)
76 where
77 <Self::Elements as Set>::Map<usize>: Clone,
78 {
79 use std::collections::btree_map::Entry;
80 let mut cache = self.initialize_cache();
81 let elements = self.elements();
82 let initial_coloring = self.initial_coloring();
83 let mut node = Some(
84 tree::Node::root(ReversibleColoring::from_coloring(
85 elements,
86 Coloring::from_map(elements, &initial_coloring),
87 ))
88 .into_first_child_leaf(|coloring| self.refine_coloring(&mut cache, coloring)),
89 );
90
91 pub struct Automorphism<T: Normalize> {
92 path: Vec<<T::Elements as Set>::Item>,
93 permutation: <T::Elements as Set>::Map<usize>,
94 }
95
96 let mut automorphisms: BTreeMap<Self::Morphed, Automorphism<Self>> = BTreeMap::new();
97
98 while let Some(mut n) = node {
99 debug_assert!(n.coloring().is_discrete());
100 let permutation = n.coloring().as_permutation().unwrap();
101 let morphed = self.apply_morphism(|i| *permutation.get(i).unwrap());
102 match automorphisms.entry(morphed) {
103 Entry::Occupied(entry) => {
104 let len = n.path().len();
110
111 let prefix_len = longest_common_prefix_len(n.path(), &entry.get().path);
113
114 n.restore(len - prefix_len - 1); }
122 Entry::Vacant(entry) => {
123 entry.insert(Automorphism {
124 path: n.path().clone(),
125 permutation: permutation.clone(),
126 });
127 }
128 }
129
130 node = n.into_next_leaf(|coloring| self.refine_coloring(&mut cache, coloring));
131 }
132
133 let (normal_form, data) = automorphisms.into_iter().next().unwrap();
134 (normal_form, data.permutation)
135 }
136}
137
138fn longest_common_prefix_len<T: PartialEq>(a: &[T], b: &[T]) -> usize {
139 let mut n = 0;
140
141 for (a, b) in a.iter().zip(b) {
142 if a == b {
143 n += 1
144 } else {
145 break;
146 }
147 }
148
149 n
150}