1 #ifdef NDEBUG
2 #undef NDEBUG
3 #endif
4
5 #include "localsat.hpp"
6 #include "config.hpp"
7 #include "dedge.hpp"
8 #include "field-math.hpp"
9
10 #include <Eigen/Core>
11
12 #include <deque>
13 #include <memory>
14 #include <utility>
15 #include <vector>
16
17 namespace qflow {
18
19 const int max_depth = 0;
20
21 using namespace Eigen;
22
RunCNF(const std::string & fin_name,int n_variable,int timeout,const std::vector<std::vector<int>> & sat_clause,std::vector<int> & value)23 SolverStatus RunCNF(const std::string &fin_name, int n_variable, int timeout,
24 const std::vector<std::vector<int>> &sat_clause, std::vector<int> &value) {
25 int n_sat_variable = 3 * n_variable;
26 auto fout_name = fin_name + ".result.txt";
27
28 FILE *fout = fopen(fin_name.c_str(), "w");
29 fprintf(fout, "p cnf %d %d\n", n_sat_variable, (int)sat_clause.size());
30 for (auto &c : sat_clause) {
31 for (auto e : c) fprintf(fout, "%d ", e);
32 fputs("0\n", fout);
33 }
34 fclose(fout);
35
36 char cmd[100];
37 snprintf(cmd, 99, "rm %s > /dev/null 2>&1", fout_name.c_str());
38 system(cmd);
39 snprintf(cmd, 99, "timeout %d minisat %s %s > /dev/null 2>&1", timeout, fin_name.c_str(),
40 fout_name.c_str());
41 int exit_code = system(cmd);
42
43 FILE *fin = fopen(fout_name.c_str(), "r");
44 char buf[16] = {0};
45 fscanf(fin, "%15s", buf);
46 lprintf(" MiniSAT:");
47 if (strcmp(buf, "SAT") != 0) {
48 fclose(fin);
49
50 if (exit_code == 124) {
51 lprintf(" Timeout! ");
52 return SolverStatus::Timeout;
53 }
54 lprintf(" Unsatisfiable! ");
55 return SolverStatus::Unsat;
56 };
57
58 lprintf(" Satisfiable! ");
59 for (int i = 0; i < n_variable; ++i) {
60 int sign[3];
61 fscanf(fin, "%d %d %d", sign + 0, sign + 1, sign + 2);
62
63 int nvalue = -2;
64 for (int j = 0; j < 3; ++j) {
65 assert(abs(sign[j]) == 3 * i + j + 1);
66 if ((sign[j] > 0) == (value[i] != j - 1)) {
67 assert(nvalue == -2);
68 nvalue = j - 1;
69 }
70 }
71 value[i] = nvalue;
72 }
73 fclose(fin);
74
75 return SolverStatus::Sat;
76 }
77
SolveSatProblem(int n_variable,std::vector<int> & value,const std::vector<bool> flexible,const std::vector<Vector3i> & variable_eq,const std::vector<Vector3i> & constant_eq,const std::vector<Vector4i> & variable_ge,const std::vector<Vector2i> & constant_ge,int timeout)78 SolverStatus SolveSatProblem(int n_variable, std::vector<int> &value,
79 const std::vector<bool> flexible, // NOQA
80 const std::vector<Vector3i> &variable_eq,
81 const std::vector<Vector3i> &constant_eq,
82 const std::vector<Vector4i> &variable_ge,
83 const std::vector<Vector2i> &constant_ge,
84 int timeout) {
85 for (int v : value) assert(-1 <= v && v <= +1);
86
87 auto VAR = [&](int i, int v) {
88 int index = 1 + 3 * i + v + 1;
89 // We initialize the SAT problem by setting all the variable to false.
90 // This is because minisat by default will try false first.
91 if (v == value[i]) index = -index;
92 return index;
93 };
94
95 int n_flexible = 0;
96 std::vector<std::vector<int>> sat_clause;
97 std::vector<bool> sat_ishard;
98
99 auto add_clause = [&](const std::vector<int> &clause, bool hard) {
100 sat_clause.push_back(clause);
101 sat_ishard.push_back(hard);
102 };
103
104 for (int i = 0; i < n_variable; ++i) {
105 add_clause({-VAR(i, -1), -VAR(i, 0)}, true);
106 add_clause({-VAR(i, +1), -VAR(i, 0)}, true);
107 add_clause({-VAR(i, -1), -VAR(i, +1)}, true);
108 add_clause({VAR(i, -1), VAR(i, 0), VAR(i, +1)}, true);
109 if (!flexible[i]) {
110 add_clause({VAR(i, value[i])}, true);
111 } else {
112 ++n_flexible;
113 }
114 }
115
116 for (int i = 0; i < (int)variable_eq.size(); ++i) {
117 auto &var = variable_eq[i];
118 auto &cst = constant_eq[i];
119 for (int v0 = -1; v0 <= 1; ++v0)
120 for (int v1 = -1; v1 <= 1; ++v1)
121 for (int v2 = -1; v2 <= 1; ++v2)
122 if (cst[0] * v0 + cst[1] * v1 + cst[2] * v2 != 0) {
123 add_clause({-VAR(var[0], v0), -VAR(var[1], v1), -VAR(var[2], v2)}, true);
124 }
125 }
126
127 for (int i = 0; i < (int)variable_ge.size(); ++i) {
128 auto &var = variable_ge[i];
129 auto &cst = constant_ge[i];
130 for (int v0 = -1; v0 <= 1; ++v0)
131 for (int v1 = -1; v1 <= 1; ++v1)
132 for (int v2 = -1; v2 <= 1; ++v2)
133 for (int v3 = -1; v3 <= 1; ++v3)
134 if (cst[0] * v0 * v1 - cst[1] * v2 * v3 < 0) {
135 add_clause({-VAR(var[0], v0), -VAR(var[1], v1), -VAR(var[2], v2),
136 -VAR(var[3], v3)},
137 false);
138 }
139 }
140
141 int nflip_before = 0, nflip_after = 0;
142 for (int i = 0; i < (int)variable_ge.size(); ++i) {
143 auto &var = variable_ge[i];
144 auto &cst = constant_ge[i];
145 if (value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1] < 0)
146 nflip_before++;
147 }
148
149 lprintf(" [SAT] nvar: %6d nflip: %3d ", n_flexible * 2, nflip_before);
150 auto rcnf = RunCNF("test.out", n_variable, timeout, sat_clause, value);
151
152 for (int i = 0; i < (int)variable_eq.size(); ++i) {
153 auto &var = variable_eq[i];
154 auto &cst = constant_eq[i];
155 assert(cst[0] * value[var[0]] + cst[1] * value[var[1]] + cst[2] * value[var[2]] == 0);
156 }
157 for (int i = 0; i < (int)variable_ge.size(); ++i) {
158 auto &var = variable_ge[i];
159 auto &cst = constant_ge[i];
160 int area = value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1];
161 if (area < 0) ++nflip_after;
162 }
163 lprintf("nflip: %3d\n", nflip_after);
164 return rcnf;
165 }
166
ExportLocalSat(std::vector<Vector2i> & edge_diff,const std::vector<Vector3i> & face_edgeIds,const std::vector<Vector3i> & face_edgeOrients,const MatrixXi & F,const VectorXi & V2E,const VectorXi & E2E)167 void ExportLocalSat(std::vector<Vector2i> &edge_diff, const std::vector<Vector3i> &face_edgeIds,
168 const std::vector<Vector3i> &face_edgeOrients, const MatrixXi &F,
169 const VectorXi &V2E, const VectorXi &E2E) {
170 int flip_count = 0;
171 int flip_count1 = 0;
172
173 std::vector<int> value(2 * edge_diff.size());
174 for (int i = 0; i < (int)edge_diff.size(); ++i) {
175 value[2 * i + 0] = edge_diff[i][0];
176 value[2 * i + 1] = edge_diff[i][1];
177 }
178
179 std::deque<std::pair<int, int>> Q;
180 std::vector<bool> mark_vertex(V2E.size(), false);
181
182 assert(F.cols() == (int)face_edgeIds.size());
183 std::vector<Vector3i> variable_eq(face_edgeIds.size() * 2);
184 std::vector<Vector3i> constant_eq(face_edgeIds.size() * 2);
185 std::vector<Vector4i> variable_ge(face_edgeIds.size());
186 std::vector<Vector2i> constant_ge(face_edgeIds.size());
187
188 VectorXd face_area(F.cols());
189
190 for (int i = 0; i < (int)face_edgeIds.size(); ++i) {
191 Vector2i diff[3];
192 Vector2i var[3];
193 Vector2i cst[3];
194 for (int j = 0; j < 3; ++j) {
195 int edgeid = face_edgeIds[i][j];
196 diff[j] = rshift90(edge_diff[edgeid], face_edgeOrients[i][j]);
197 var[j] = rshift90(Vector2i(edgeid * 2 + 1, edgeid * 2 + 2), face_edgeOrients[i][j]);
198 cst[j] = var[j].array().sign();
199 var[j] = var[j].array().abs() - 1;
200 }
201
202 assert(diff[0] + diff[1] + diff[2] == Vector2i::Zero());
203 variable_eq[2 * i + 0] = Vector3i(var[0][0], var[1][0], var[2][0]);
204 constant_eq[2 * i + 0] = Vector3i(cst[0][0], cst[1][0], cst[2][0]);
205 variable_eq[2 * i + 1] = Vector3i(var[0][1], var[1][1], var[2][1]);
206 constant_eq[2 * i + 1] = Vector3i(cst[0][1], cst[1][1], cst[2][1]);
207
208 face_area[i] = diff[0][0] * diff[1][1] - diff[0][1] * diff[1][0];
209 if (face_area[i] < 0) {
210 printf("[SAT] Face %d's area < 0\n", i);
211 for (int j = 0; j < 3; ++j) {
212 int v = F(j, i);
213 if (mark_vertex[v]) continue;
214 Q.push_back(std::make_pair(v, 0));
215 mark_vertex[v] = true;
216 }
217 flip_count += 1;
218 }
219 variable_ge[i] = Vector4i(var[0][0], var[1][1], var[0][1], var[1][0]);
220 constant_ge[i] = Vector2i(cst[0][0] * cst[1][1], cst[0][1] * cst[1][0]);
221 }
222 for (int i = 0; i < (int)variable_eq.size(); ++i) {
223 auto &var = variable_eq[i];
224 auto &cst = constant_eq[i];
225 assert((0 <= var.array()).all());
226 assert((var.array() < value.size()).all());
227 assert(cst[0] * value[var[0]] + cst[1] * value[var[1]] + cst[2] * value[var[2]] == 0);
228 }
229
230 for (int i = 0; i < (int)variable_ge.size(); ++i) {
231 auto &var = variable_ge[i];
232 auto &cst = constant_ge[i];
233 assert((0 <= variable_ge[i].array()).all());
234 assert((variable_ge[i].array() < value.size()).all());
235 if (value[var[0]] * value[var[1]] * cst[0] - value[var[2]] * value[var[3]] * cst[1] < 0) {
236 assert(face_area[i] < 0);
237 flip_count1++;
238 }
239 }
240 assert(flip_count == flip_count1);
241
242 // BFS
243 printf("[SAT] Start BFS: Q.size() = %d\n", (int)Q.size());
244
245 int mark_count = Q.size();
246 while (!Q.empty()) {
247 int vertex = Q.front().first;
248 int depth = Q.front().second;
249 Q.pop_front();
250 mark_count++;
251 int e0 = V2E(vertex);
252
253 for (int e = e0;;) {
254 int v = F((e + 1) % 3, e / 3);
255 if (!mark_vertex[v]) {
256 int undirected_edge_id = face_edgeIds[e / 3][e % 3];
257 int undirected_edge_length = edge_diff[undirected_edge_id].array().abs().sum() > 0;
258 int ndepth = depth + undirected_edge_length;
259 if (ndepth <= max_depth) {
260 if (undirected_edge_length == 0)
261 Q.push_front(std::make_pair(v, ndepth));
262 else
263 Q.push_back(std::make_pair(v, ndepth));
264 mark_vertex[v] = true;
265 }
266 }
267 e = dedge_next_3(E2E(e));
268 if (e == e0) break;
269 }
270 }
271 printf("[SAT] Mark %d vertices out of %d\n", mark_count, (int)V2E.size());
272
273 std::vector<bool> flexible(value.size(), false);
274 for (int i = 0; i < (int)face_edgeIds.size(); ++i) {
275 for (int j = 0; j < 3; ++j) {
276 int edgeid = face_edgeIds[i][j];
277 if (mark_vertex[F(j, i)] || mark_vertex[F((j + 1) % 3, i)]) {
278 flexible[edgeid * 2 + 0] = true;
279 flexible[edgeid * 2 + 1] = true;
280 } else {
281 assert(face_area[i] >= 0);
282 }
283 }
284 }
285
286 SolveSatProblem(value.size(), value, flexible, variable_eq, constant_eq, variable_ge,
287 constant_ge);
288
289 for (int i = 0; i < edge_diff.size(); ++i) {
290 edge_diff[i][0] = value[2 * i + 0];
291 edge_diff[i][1] = value[2 * i + 1];
292 }
293 }
294
295 } // namespace qflow
296