24 const std::vector<std::unique_ptr<SparsePermutation>>& generators) {
27 std::vector<std::vector<int>> num_cycles_to_2cyclers;
28 for (
int g = 0; g < generators.size(); ++g) {
29 const std::unique_ptr<SparsePermutation>& perm = generators[g];
30 bool contain_only_2cycles =
true;
31 const int num_cycles = perm->NumCycles();
32 for (
int i = 0; i < num_cycles; ++i) {
33 if (perm->Cycle(i).size() != 2) {
34 contain_only_2cycles =
false;
38 if (!contain_only_2cycles)
continue;
39 if (num_cycles >= num_cycles_to_2cyclers.size()) {
40 num_cycles_to_2cyclers.resize(num_cycles + 1);
42 num_cycles_to_2cyclers[num_cycles].push_back(g);
51 for (
int i = 0; i < num_cycles_to_2cyclers.size(); ++i) {
52 if (num_cycles_to_2cyclers[i].size() > 1) {
53 const int num_perms = num_cycles_to_2cyclers[i].size() + 1;
54 VLOG(1) <<
"Potential orbitope: " << i <<
" x " << num_perms;
55 const int64_t score =
std::min(i, num_perms);
56 if (score > best_score) {
63 std::vector<std::vector<int>> orbitope;
64 if (best == -1)
return orbitope;
67 std::vector<bool> in_matrix;
70 orbitope.resize(best);
71 for (
const int g : num_cycles_to_2cyclers[best]) {
73 if (orbitope[0].empty()) {
74 const std::unique_ptr<SparsePermutation>& perm = generators[g];
75 const int num_cycles = perm->NumCycles();
76 for (
int i = 0; i < num_cycles; ++i) {
77 for (
const int x : perm->Cycle(i)) {
78 orbitope[i].push_back(x);
79 if (x >= in_matrix.size()) in_matrix.resize(x + 1,
false);
94 std::vector<int> grow;
95 int matching_column_index = -1;
96 const std::unique_ptr<SparsePermutation>& perm = generators[g];
97 const int num_cycles = perm->NumCycles();
98 for (
int i = 0; i < num_cycles; ++i) {
100 std::vector<int> tmp;
101 for (
const int x : perm->Cycle(i)) tmp.push_back(x);
102 const int a = tmp[0];
103 const int b = tmp[1];
107 int num_matches_a = 0;
108 int num_matches_b = 0;
109 int last_match_index = -1;
110 for (
int j = 0; j < orbitope[i].size(); ++j) {
111 if (orbitope[i][j] ==
a) {
113 last_match_index = j;
114 }
else if (orbitope[i][j] ==
b) {
116 last_match_index = j;
119 if (last_match_index == -1)
break;
120 if (matching_column_index == -1) {
121 matching_column_index = last_match_index;
123 if (matching_column_index != last_match_index)
break;
124 if (num_matches_a == 0 && num_matches_b == 1) {
125 if (
a >= in_matrix.size() || !in_matrix[
a]) grow.push_back(
a);
126 }
else if (num_matches_a == 1 && num_matches_b == 0) {
127 if (
b >= in_matrix.size() || !in_matrix[
b]) grow.push_back(
b);
134 if (grow.size() == num_cycles) {
135 for (
int i = 0; i < orbitope.size(); ++i) {
136 orbitope[i].push_back(grow[i]);
137 if (grow[i] >= in_matrix.size()) in_matrix.resize(grow[i] + 1,
false);
138 in_matrix[grow[i]] =
true;
147 int n,
const std::vector<std::unique_ptr<SparsePermutation>>& generators) {
150 for (
const std::unique_ptr<SparsePermutation>& perm : generators) {
151 const int num_cycles = perm->NumCycles();
152 for (
int i = 0; i < num_cycles; ++i) {
155 bool is_first =
true;
156 for (
const int x : perm->Cycle(i)) {
168 std::vector<int> orbits(n, -1);
169 for (
int i = 0; i < n; ++i) {
172 if (orbits[root] == -1) orbits[root] = num_parts++;
173 orbits[i] = orbits[root];
179 int n,
const std::vector<std::vector<int>>& orbitope) {
180 std::vector<int> orbits(n, -1);
181 for (
int i = 0; i < orbitope.size(); ++i) {
182 for (
int j = 0; j < orbitope[i].size(); ++j) {
183 CHECK_EQ(orbits[orbitope[i][j]], -1);
184 orbits[orbitope[i][j]] = i;
#define CHECK_EQ(val1, val2)
#define VLOG(verboselevel)
int NumNodesInSamePartAs(int node)
void Reset(int num_nodes)
int MergePartsOf(int node1, int node2)
int GetRootAndCompressPath(int node)
std::vector< int > GetOrbitopeOrbits(int n, const std::vector< std::vector< int >> &orbitope)
std::vector< std::vector< int > > BasicOrbitopeExtraction(const std::vector< std::unique_ptr< SparsePermutation >> &generators)
std::vector< int > GetOrbits(int n, const std::vector< std::unique_ptr< SparsePermutation >> &generators)
Collection of objects used to extend the Constraint Solver library.