31 absl::Span<
const std::unique_ptr<SparsePermutation>> generators) {
34 std::vector<std::vector<int>> num_cycles_to_2cyclers;
35 for (
int g = 0; g < generators.size(); ++g) {
36 const std::unique_ptr<SparsePermutation>& perm = generators[g];
37 bool contain_only_2cycles =
true;
38 const int num_cycles = perm->NumCycles();
39 for (
int i = 0;
i < num_cycles; ++
i) {
40 if (perm->Cycle(
i).size() != 2) {
41 contain_only_2cycles =
false;
45 if (!contain_only_2cycles)
continue;
46 if (num_cycles >= num_cycles_to_2cyclers.size()) {
47 num_cycles_to_2cyclers.resize(num_cycles + 1);
49 num_cycles_to_2cyclers[num_cycles].push_back(g);
58 for (
int i = 0;
i < num_cycles_to_2cyclers.size(); ++
i) {
59 if (num_cycles_to_2cyclers[
i].
size() > 1) {
60 const int num_perms = num_cycles_to_2cyclers[
i].size() + 1;
61 VLOG(1) <<
"Potential orbitope: " <<
i <<
" x " << num_perms;
62 const int64_t score = std::min(
i, num_perms);
63 if (score > best_score) {
70 std::vector<std::vector<int>> orbitope;
71 if (best == -1)
return orbitope;
74 std::vector<bool> in_matrix;
77 orbitope.resize(best);
78 for (
const int g : num_cycles_to_2cyclers[best]) {
80 if (orbitope[0].empty()) {
81 const std::unique_ptr<SparsePermutation>& perm = generators[g];
82 const int num_cycles = perm->NumCycles();
83 for (
int i = 0;
i < num_cycles; ++
i) {
84 for (
const int x : perm->Cycle(
i)) {
85 orbitope[
i].push_back(
x);
86 if (
x >= in_matrix.size()) in_matrix.resize(
x + 1,
false);
101 std::vector<int> grow;
102 int matching_column_index = -1;
103 const std::unique_ptr<SparsePermutation>& perm = generators[g];
104 const int num_cycles = perm->NumCycles();
105 for (
int i = 0;
i < num_cycles; ++
i) {
107 std::vector<int> tmp;
108 for (
const int x : perm->Cycle(
i)) tmp.push_back(
x);
109 const int a = tmp[0];
110 const int b = tmp[1];
114 int num_matches_a = 0;
115 int num_matches_b = 0;
116 int last_match_index = -1;
117 for (
int j = 0; j < orbitope[
i].size(); ++j) {
118 if (orbitope[
i][j] ==
a) {
120 last_match_index = j;
121 }
else if (orbitope[
i][j] ==
b) {
123 last_match_index = j;
126 if (last_match_index == -1)
break;
127 if (matching_column_index == -1) {
128 matching_column_index = last_match_index;
130 if (matching_column_index != last_match_index)
break;
131 if (num_matches_a == 0 && num_matches_b == 1) {
132 if (
a >= in_matrix.size() || !in_matrix[
a]) grow.push_back(
a);
133 }
else if (num_matches_a == 1 && num_matches_b == 0) {
134 if (
b >= in_matrix.size() || !in_matrix[
b]) grow.push_back(
b);
141 if (grow.size() == num_cycles) {
142 for (
int i = 0;
i < orbitope.size(); ++
i) {
143 orbitope[
i].push_back(grow[
i]);
144 if (grow[
i] >= in_matrix.size()) in_matrix.resize(grow[
i] + 1,
false);
145 in_matrix[grow[
i]] =
true;
154 int n, absl::Span<
const std::unique_ptr<SparsePermutation>> generators) {
157 for (
const std::unique_ptr<SparsePermutation>& perm : generators) {
158 const int num_cycles = perm->NumCycles();
159 for (
int i = 0;
i < num_cycles; ++
i) {
162 bool is_first =
true;
163 for (
const int x : perm->Cycle(
i)) {
175 std::vector<int> orbits(n, -1);
176 for (
int i = 0;
i < n; ++
i) {
179 if (orbits[root] == -1) orbits[root] = num_parts++;
180 orbits[
i] = orbits[root];