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