32 absl::Span<
const std::unique_ptr<SparsePermutation>> generators) {
35 std::vector<std::vector<int>> num_cycles_to_2cyclers;
36 for (
int g = 0; g < generators.size(); ++g) {
37 const std::unique_ptr<SparsePermutation>& perm = generators[g];
38 bool contain_only_2cycles =
true;
39 const int num_cycles = perm->NumCycles();
40 for (
int i = 0;
i < num_cycles; ++
i) {
41 if (perm->Cycle(
i).size() != 2) {
42 contain_only_2cycles =
false;
46 if (!contain_only_2cycles)
continue;
47 if (num_cycles >= num_cycles_to_2cyclers.size()) {
48 num_cycles_to_2cyclers.resize(num_cycles + 1);
50 num_cycles_to_2cyclers[num_cycles].push_back(g);
59 for (
int i = 0;
i < num_cycles_to_2cyclers.size(); ++
i) {
60 if (num_cycles_to_2cyclers[
i].size() > 1) {
61 const int num_perms = num_cycles_to_2cyclers[
i].size() + 1;
62 VLOG(1) <<
"Potential orbitope: " <<
i <<
" x " << num_perms;
63 const int64_t score = std::min(
i, num_perms);
64 if (score > best_score) {
71 std::vector<std::vector<int>> orbitope;
72 if (best == -1)
return orbitope;
75 std::vector<bool> in_matrix;
78 orbitope.resize(best);
79 for (
const int g : num_cycles_to_2cyclers[best]) {
81 if (orbitope[0].empty()) {
82 const std::unique_ptr<SparsePermutation>& perm = generators[g];
83 const int num_cycles = perm->NumCycles();
84 for (
int i = 0;
i < num_cycles; ++
i) {
85 for (
const int x : perm->Cycle(
i)) {
86 orbitope[
i].push_back(x);
87 if (x >= in_matrix.size()) in_matrix.resize(x + 1,
false);
102 std::vector<int> grow;
103 int matching_column_index = -1;
104 const std::unique_ptr<SparsePermutation>& perm = generators[g];
105 const int num_cycles = perm->NumCycles();
106 for (
int i = 0;
i < num_cycles; ++
i) {
108 std::vector<int> tmp;
109 for (
const int x : perm->Cycle(
i)) tmp.push_back(x);
110 const int a = tmp[0];
111 const int b = tmp[1];
115 int num_matches_a = 0;
116 int num_matches_b = 0;
117 int last_match_index = -1;
118 for (
int j = 0; j < orbitope[
i].size(); ++j) {
119 if (orbitope[
i][j] == a) {
121 last_match_index = j;
122 }
else if (orbitope[
i][j] ==
b) {
124 last_match_index = j;
127 if (last_match_index == -1)
break;
128 if (matching_column_index == -1) {
129 matching_column_index = last_match_index;
131 if (matching_column_index != last_match_index)
break;
132 if (num_matches_a == 0 && num_matches_b == 1) {
133 if (a >= in_matrix.size() || !in_matrix[a]) grow.push_back(a);
134 }
else if (num_matches_a == 1 && num_matches_b == 0) {
135 if (
b >= in_matrix.size() || !in_matrix[
b]) grow.push_back(
b);
142 if (grow.size() == num_cycles) {
143 for (
int i = 0;
i < orbitope.size(); ++
i) {
144 orbitope[
i].push_back(grow[
i]);
145 if (grow[
i] >= in_matrix.size()) in_matrix.resize(grow[
i] + 1,
false);
146 in_matrix[grow[
i]] =
true;
155 int n, absl::Span<
const std::unique_ptr<SparsePermutation>> generators) {
158 for (
const std::unique_ptr<SparsePermutation>& perm : generators) {
159 DCHECK(perm !=
nullptr);
160 const int num_cycles = perm->NumCycles();
161 for (
int i = 0;
i < num_cycles; ++
i) {
164 bool is_first =
true;
165 for (
const int x : perm->Cycle(
i)) {
179 std::vector<int> orbits(n, -1);
180 for (
int i = 0;
i < n; ++
i) {
183 if (orbits[root] == -1) orbits[root] = num_parts++;
184 orbits[
i] = orbits[root];
202 int point, absl::Span<
const std::unique_ptr<SparsePermutation>> generators,
203 std::vector<int>* schrier_vector, std::vector<int>* orbit) {
204 schrier_vector->clear();
206 if (generators.empty())
return;
207 schrier_vector->resize(generators[0]->Size(), -1);
208 absl::flat_hash_set<int> orbit_set = {point};
209 for (
int i = 0;
i < orbit->size(); ++
i) {
210 const int orbit_element = (*orbit)[
i];
211 for (
int i = 0;
i < generators.size(); ++
i) {
212 DCHECK_EQ(schrier_vector->size(), generators[
i]->Size());
213 const int image = generators[
i]->Image(orbit_element);
214 if (image == orbit_element)
continue;
215 const auto [it, inserted] = orbit_set.insert(image);
217 (*schrier_vector)[image] =
i;
218 orbit->push_back(image);
225 int point, absl::Span<const int> schrier_vector,
226 absl::Span<
const std::unique_ptr<SparsePermutation>> generators) {
227 std::vector<int> result;
228 while (schrier_vector[point] != -1) {
230 result.push_back(schrier_vector[point]);
232 DCHECK_NE(next, point);
239 int n,
const SparsePermutationProto& proto) {
240 auto perm = std::make_unique<SparsePermutation>(n);
241 int support_index = 0;
242 const int num_cycle = proto.cycle_sizes().size();
243 for (
int i = 0;
i < num_cycle; ++
i) {
244 const int size = proto.cycle_sizes(
i);
245 for (
int j = 0; j < size; ++j) {
246 DCHECK_LT(proto.support(support_index), n);
247 perm->AddToCurrentCycle(proto.support(support_index++));
249 perm->CloseCurrentCycle();