ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
rrrSatSolver.h
Go to the documentation of this file.
1#pragma once
2
4
5#include "rrrParameter.h"
6#include "rrrUtils.h"
7
9
10namespace rrr {
11
12 template <typename Ntk>
13 class SatSolver {
14 private:
15 // pointer to network
16 Ntk *pNtk;
17
18 // parameters
19 int nVerbose;
20 int nConflictLimit;
21
22 // data
23 sat_solver *pSat;
24 bool status; // false indicates trivial UNSAT
25 int target; // node for which miter has been encoded
26 std::vector<int> vVars; // SAT variable for each node
27 std::vector<int> vLits; // temporary storage
28 std::vector<VarValue> vValues; // values in satisfied problem
29 bool fUpdate;
30
31 // stats
32 int nCalls;
33 int nSats;
34 int nUnsats;
35 double durationRedundancy;
36 double durationFeasibility;
37
38 // callback
39 void ActionCallback(Action const &action);
40
41 // encode
42 void EncodeNode(sat_solver *p, std::vector<int> const &v, int id, int to_negate = -1) const;
43 void EncodeMiter(sat_solver *p, std::vector<int> &v, int id); // create a careset miter where the counterpart has the output of target negated
44 void SetTarget(int id);
45
46 public:
47 // constructors
48 SatSolver(Parameter const *pPar);
49 ~SatSolver();
50 void AssignNetwork(Ntk *pNtk_, bool fReuse);
51
52 // checks
53 SatResult CheckRedundancy(int id, int idx);
54 SatResult CheckFeasibility(int id, int fi, bool c);
55
56 // cex
57 std::vector<VarValue> GetCex();
58
59 // stats
60 void ResetSummary();
63 };
64
65 /* {{{ Callback */
66
67 template <typename Ntk>
68 void SatSolver<Ntk>::ActionCallback(Action const &action) {
69 if(target == -1) {
70 return;
71 }
72 switch(action.type) {
73 case REMOVE_FANIN:
74 if(action.id != target) {
75 fUpdate = true;
76 }
77 break;
78 case REMOVE_UNUSED:
79 break;
80 case REMOVE_BUFFER:
81 case REMOVE_CONST:
82 if(action.id == target) {
83 target = -1;
84 }
85 break;
86 case ADD_FANIN:
87 if(action.id != target) {
88 fUpdate = true;
89 }
90 break;
92 break;
94 fUpdate = true;
95 break;
96 case SORT_FANINS:
97 break;
98 case READ:
99 status = false;
100 target = -1;
101 fUpdate = false;
102 break;
103 case SAVE:
104 break;
105 case LOAD:
106 target = -1;
107 break;
108 case POP_BACK:
109 break;
110 default:
111 assert(0);
112 }
113 }
114
115 /* }}} */
116
117 /* {{{ Encode */
118
119 template <typename Ntk>
120 void SatSolver<Ntk>::EncodeNode(sat_solver *p, std::vector<int> const &v, int id, int to_negate) const {
121 int RetValue;
122 int x = -1, y = -1;
123 bool cx = false, cy = false;
124 assert(pNtk->GetNodeType(id) == AND);
125 std::string delim;
126 if(nVerbose) {
127 std::cout << "node " << std::setw(3) << id << ": ";
128 }
129 pNtk->ForEachFanin(id, [&](int fi, bool c) {
130 if(x == -1) {
131 x = v[fi];
132 cx = c ^ (fi == to_negate);
133 } else if(y == -1) {
134 y = v[fi];
135 cy = c ^ (fi == to_negate);
136 } else {
137 int z = sat_solver_addvar(p);
138 if(nVerbose) {
139 std::cout << delim << z << " = " << (cx? "!": "") << x << " & " << (cy? "!": "") << y << std::endl;
140 delim = std::string(10, ' ');
141 }
142 RetValue = sat_solver_add_and(p, z, x, y, cx, cy, 0);
143 assert(RetValue);
144 x = z;
145 cx = false;
146 y = v[fi];
147 cy = c ^ (fi == to_negate);
148 }
149 });
150 if(x == -1) {
151 if(nVerbose) {
152 std::cout << delim << v[id] << " = !0" << std::endl;
153 }
154 RetValue = sat_solver_add_const(p, v[id], 0);
155 assert(RetValue);
156 } else if(y == -1) {
157 if(nVerbose) {
158 std::cout << delim << v[id] << " = " << (cx? "!": "") << x << std::endl;
159 }
160 RetValue = sat_solver_add_buffer(p, v[id], x, cx);
161 assert(RetValue);
162 } else {
163 if(nVerbose) {
164 std::cout << delim << v[id] << " = " << (cx? "!": "") << x << " & " << (cy? "!": "") << y << std::endl;
165 }
166 RetValue = sat_solver_add_and(p, v[id], x, y, cx, cy, 0);
167 assert(RetValue);
168 }
169 }
170
171 template <typename Ntk>
172 void SatSolver<Ntk>::EncodeMiter(sat_solver *p, std::vector<int> &v, int id) {
173 int RetValue;
174 // reset
175 v.clear();
177 status = true;
178 // assign vars for the base
179 int nNodes = pNtk->GetNumNodes();
180 sat_solver_setnvars(p, nNodes);
181 v.resize(nNodes);
182 for(int i = 0; i < nNodes; i++) {
183 v[i] = i;
184 }
185 // constrain const-0
186 RetValue = sat_solver_add_const(p, v[0], 1);
187 assert(RetValue);
188 // encode first circuit
189 if(nVerbose) {
190 std::cout << "encoding network" << std::endl;
191 }
192 pNtk->ForEachInt([&](int id) {
193 EncodeNode(p, v, id);
194 });
195 // always care if it is po
196 if(pNtk->IsPoDriver(id)) {
197 return;
198 }
199 // store po vars (NOTE: it's not a lit)
200 vLits.clear();
201 pNtk->ForEachPoDriver([&](int fi) {
202 vLits.push_back(v[fi]);
203 });
204 // encode an inverted copy
205 if(nVerbose) {
206 std::cout << "encoding an inverted copy" << std::endl;
207 }
208 pNtk->ForEachTfo(id, false, [&](int fo) {
209 v[fo] = sat_solver_addvar(p);
210 EncodeNode(p, v, fo, id);
211 });
212 // encode miter xors
213 if(nVerbose) {
214 std::cout << "encoding miter xors" << std::endl;
215 }
216 int idx = 0;
217 int n = 0;
218 pNtk->ForEachPoDriver([&](int fi) {
219 assert(fi != id);
220 if(v[fi] != vLits[idx]) {
221 int x = sat_solver_addvar(p);
222 if(nVerbose) {
223 std::cout << x << " = " << v[fi] << " ^ " << vLits[idx] << std::endl;
224 }
225 RetValue = sat_solver_add_xor(p, x, v[fi], vLits[idx], 0);
226 assert(RetValue);
227 vLits[n] = toLitCond(x, 0);
228 n++;
229 }
230 idx++;
231 });
232 vLits.resize(n);
233 // assign or of xors to 1
234 if(nVerbose) {
235 std::cout << "adding miter output clause" << std::endl;
236 std::cout << "(";
237 std::string delim = "";
238 for(int iLit: vLits) {
239 std::cout << delim << (lit_sign(iLit)? "!": "") << lit_var(iLit);
240 delim = ", ";
241 }
242 std::cout << ")" << std::endl;
243 }
244 if(n == 0) {
245 status = false;
246 return;
247 }
248 RetValue = sat_solver_addclause(p, vLits.data(), vLits.data() + n);
249 assert(RetValue);
250 }
251
252 template <typename Ntk>
253 void SatSolver<Ntk>::SetTarget(int id) {
254 if(!fUpdate && id == target) {
255 return;
256 }
257 fUpdate = false;
258 target = id;
259 EncodeMiter(pSat, vVars, target);
260 }
261
262 /* }}} */
263
264 /* {{{ Constructors */
265
266 template <typename Ntk>
268 pNtk(NULL),
269 nVerbose(pPar->nSatSolverVerbose),
270 nConflictLimit(pPar->nConflictLimit),
271 pSat(sat_solver_new()),
272 status(false),
273 target(-1),
274 fUpdate(false) {
275 ResetSummary();
276 }
277
278 template <typename Ntk>
280 sat_solver_delete(pSat);
281 //std::cout << "SAT solver stats: calls = " << nCalls << " (SAT = " << nSats << ", UNSAT = " << nUnsats << ", UNDET = " << nCalls - nSats - nUnsats << ")" << std::endl;
282 }
283
284 template <typename Ntk>
285 void SatSolver<Ntk>::AssignNetwork(Ntk *pNtk_, bool fReuse) {
286 (void)fReuse;
287 status = false;
288 target = -1;
289 fUpdate = false;
290 pNtk = pNtk_;
291 pNtk->AddCallback(std::bind(&SatSolver<Ntk>::ActionCallback, this, std::placeholders::_1));
292 }
293
294 /* }}} */
295
296 /* {{{ Checks */
297
298 template <typename Ntk>
300 time_point timeStart = GetCurrentTime();
301 SetTarget(id);
302 if(!status) {
303 if(nVerbose) {
304 std::cout << "trivially UNSATISFIABLE" << std::endl;
305 }
306 durationRedundancy += Duration(timeStart, GetCurrentTime());
307 return UNSAT;
308 }
309 vLits.clear();
310 assert(pNtk->GetNodeType(id) == AND);
311 pNtk->ForEachFaninIdx(id, [&](int idx2, int fi, bool c) {
312 if(idx == idx2) {
313 vLits.push_back(toLitCond(vVars[fi], !c));
314 } else {
315 vLits.push_back(toLitCond(vVars[fi], c));
316 }
317 });
318 if(nVerbose) {
319 std::cout << "solving with assumptions: ";
320 std::string delim = "";
321 for(int iLit: vLits) {
322 std::cout << delim << (lit_sign(iLit)? "!": "") << lit_var(iLit);
323 delim = ", ";
324 }
325 std::cout << std::endl;
326 }
327 nCalls++;
328 int res = sat_solver_solve(pSat, vLits.data(), vLits.data() + vLits.size(), nConflictLimit, 0 /*nInsLimit*/, 0 /*nConfLimitGlobal*/, 0 /*nInsLimitGlobal*/);
329 if(res == l_False) {
330 if(nVerbose) {
331 std::cout << "UNSATISFIABLE" << std::endl;
332 }
333 nUnsats++;
334 durationRedundancy += Duration(timeStart, GetCurrentTime());
335 return UNSAT;
336 }
337 if(res == l_Undef) {
338 if(nVerbose) {
339 std::cout << "UNDETERMINED" << std::endl;
340 }
341 durationRedundancy += Duration(timeStart, GetCurrentTime());
342 return UNDET;
343 }
344 assert(res == l_True);
345 if(nVerbose) {
346 std::cout << "SATISFIABLE" << std::endl;
347 }
348 nSats++;
349 vValues.clear();
350 vValues.resize(pNtk->GetNumNodes());
351 pNtk->ForEachPi([&](int id) {
352 if(sat_solver_var_value(pSat, vVars[id])) {
353 vValues[id] = TEMP_TRUE;
354 } else {
355 vValues[id] = TEMP_FALSE;
356 }
357 });
358 pNtk->ForEachInt([&](int id) {
359 if(sat_solver_var_value(pSat, vVars[id])) {
360 vValues[id] = TEMP_TRUE;
361 } else {
362 vValues[id] = TEMP_FALSE;
363 }
364 });
365 // required values
366 pNtk->ForEachFaninIdx(id, [&](int idx2, int fi, bool c) {
367 assert((vValues[fi] == TEMP_TRUE) ^ (idx == idx2) ^ c);
368 vValues[fi] = DecideVarValue(vValues[fi]);
369 });
370 durationRedundancy += Duration(timeStart, GetCurrentTime());
371 return SAT;
372 }
373
374 template <typename Ntk>
376 time_point timeStart = GetCurrentTime();
377 SetTarget(id);
378 if(!status) {
379 if(nVerbose) {
380 std::cout << "trivially UNSATISFIABLE" << std::endl;
381 }
382 durationFeasibility += Duration(timeStart, GetCurrentTime());
383 return UNSAT;
384 }
385 vLits.clear();
386 assert(pNtk->GetNodeType(id) == AND);
387 vLits.push_back(toLit(vVars[id]));
388 vLits.push_back(toLitCond(vVars[fi], !c));
389 if(nVerbose) {
390 std::cout << "solving with assumptions: ";
391 std::string delim = "";
392 for(int iLit: vLits) {
393 std::cout << delim << (lit_sign(iLit)? "!": "") << lit_var(iLit);
394 delim = ", ";
395 }
396 std::cout << std::endl;
397 }
398 nCalls++;
399 int res = sat_solver_solve(pSat, vLits.data(), vLits.data() + vLits.size(), nConflictLimit, 0 /*nInsLimit*/, 0 /*nConfLimitGlobal*/, 0 /*nInsLimitGlobal*/);
400 if(res == l_False) {
401 if(nVerbose) {
402 std::cout << "UNSATISFIABLE" << std::endl;
403 }
404 nUnsats++;
405 durationFeasibility += Duration(timeStart, GetCurrentTime());
406 return UNSAT;
407 }
408 if(res == l_Undef) {
409 if(nVerbose) {
410 std::cout << "UNDETERMINED" << std::endl;
411 }
412 durationFeasibility += Duration(timeStart, GetCurrentTime());
413 return UNDET;
414 }
415 assert(res == l_True);
416 if(nVerbose) {
417 std::cout << "SATISFIABLE" << std::endl;
418 }
419 nSats++;
420 vValues.clear();
421 vValues.resize(pNtk->GetNumNodes());
422 pNtk->ForEachPi([&](int id) {
423 if(sat_solver_var_value(pSat, vVars[id])) {
424 vValues[id] = TEMP_TRUE;
425 } else {
426 vValues[id] = TEMP_FALSE;
427 }
428 });
429 pNtk->ForEachInt([&](int id) {
430 if(sat_solver_var_value(pSat, vVars[id])) {
431 vValues[id] = TEMP_TRUE;
432 } else {
433 vValues[id] = TEMP_FALSE;
434 }
435 });
436 // required values
437 assert(vValues[id] == TEMP_TRUE);
438 vValues[id] = DecideVarValue(vValues[id]);
439 assert((vValues[fi] == TEMP_TRUE) ^ !c);
440 vValues[fi] = DecideVarValue(vValues[fi]);
441 durationFeasibility += Duration(timeStart, GetCurrentTime());
442 return SAT;
443 }
444
445 /* }}} */
446
447 /* {{{ Cex */
448
449 template <typename Ntk>
450 std::vector<VarValue> SatSolver<Ntk>::GetCex() {
451 if(nVerbose) {
452 std::cout << "cex: ";
453 pNtk->ForEachPi([&](int id) {
454 std::cout << GetVarValueChar(vValues[id]);
455 });
456 std::cout << std::endl;
457 }
458 // reverse simulation
459 pNtk->ForEachIntReverse([&](int id) {
460 switch(pNtk->GetNodeType(id)) {
461 case AND:
462 if(vValues[id] == TRUE) {
463 pNtk->ForEachFanin(id, [&](int fi, bool c) {
464 assert((vValues[fi] == TEMP_TRUE || vValues[fi] == TRUE) ^ c);
465 vValues[fi] = DecideVarValue(vValues[fi]);
466 });
467 } else if(vValues[id] == FALSE) {
468 bool fFound = false;
469 pNtk->ForEachFanin(id, [&](int fi, bool c) {
470 if(fFound) {
471 return;
472 }
473 if(c) {
474 if(vValues[fi] == TRUE) {
475 fFound = true;
476 }
477 } else {
478 if(vValues[fi] == FALSE) {
479 fFound = true;
480 }
481 }
482 });
483 if(!fFound) {
484 pNtk->ForEachFanin(id, [&](int fi, bool c) {
485 if(fFound) {
486 return;
487 }
488 if(c) {
489 if(vValues[fi] == TEMP_TRUE) {
490 fFound = true;
491 vValues[fi] = DecideVarValue(vValues[fi]);
492 }
493 } else {
494 if(vValues[fi] == TEMP_FALSE) {
495 fFound = true;
496 vValues[fi] = DecideVarValue(vValues[fi]);
497 }
498 }
499 });
500 }
501 }
502 break;
503 default:
504 assert(0);
505 }
506 });
507 if(nVerbose) {
508 std::cout << "pex: ";
509 pNtk->ForEachPi([&](int id) {
510 std::cout << GetVarValueChar(vValues[id]);
511 });
512 std::cout << std::endl;
513 }
514 // debug
515 pNtk->ForEachInt([&](int id) {
516 switch(pNtk->GetNodeType(id)) {
517 case AND:
518 if(vValues[id] == TRUE) {
519 pNtk->ForEachFanin(id, [&](int fi, bool c) {
520 assert(c || vValues[fi] == TRUE);
521 assert(!c || vValues[fi] == FALSE);
522 });
523 } else if(vValues[id] == FALSE) {
524 bool fFound = false;
525 pNtk->ForEachFanin(id, [&](int fi, bool c) {
526 if(fFound) {
527 return;
528 }
529 if(c) {
530 if(vValues[fi] == TRUE) {
531 fFound = true;
532 }
533 } else {
534 if(vValues[fi] == FALSE) {
535 fFound = true;
536 }
537 }
538 });
539 assert(fFound);
540 }
541 break;
542 default:
543 assert(0);
544 }
545 });
546 // retrieve partial cex
547 std::vector<VarValue> vPartialCex;
548 pNtk->ForEachPi([&](int id) {
549 if(vValues[id] == TRUE || vValues[id] == FALSE) {
550 vPartialCex.push_back(vValues[id]);
551 } else {
552 vPartialCex.push_back(UNDEF);
553 }
554 });
555 return vPartialCex;
556 }
557
558 /* }}} */
559
560 /* {{{ Stats */
561
562 template <typename Ntk>
564 nCalls = 0;
565 nSats = 0;
566 nUnsats = 0;
567 durationRedundancy = 0;
568 durationFeasibility = 0;
569 }
570
571 template <typename Ntk>
573 summary<int> v;
574 v.emplace_back("sat call", nCalls);
575 v.emplace_back("sat satisfiable", nSats);
576 v.emplace_back("sat unsatisfiable", nUnsats);
577 return v;
578 }
579
580 template <typename Ntk>
583 v.emplace_back("sat redundancy", durationRedundancy);
584 v.emplace_back("sat feasibility", durationFeasibility);
585 return v;
586 }
587
588 /* }}} */
589
590}
591
#define ABC_NAMESPACE_CXX_HEADER_START
#define ABC_NAMESPACE_CXX_HEADER_END
#define l_True
Definition bmcBmcS.c:35
#define l_Undef
Definition bmcBmcS.c:34
#define l_False
Definition bmcBmcS.c:36
#define sat_solver_addclause
Definition cecSatG2.c:37
#define sat_solver_addvar
Definition cecSatG2.c:40
#define sat_solver_add_and
Definition cecSatG2.c:38
#define sat_solver_add_xor
Definition cecSatG2.c:39
#define sat_solver
Definition cecSatG2.c:34
#define sat_solver_solve
Definition cecSatG2.c:45
summary< int > GetStatsSummary() const
std::vector< VarValue > GetCex()
SatSolver(Parameter const *pPar)
SatResult CheckFeasibility(int id, int fi, bool c)
void AssignNetwork(Ntk *pNtk_, bool fReuse)
summary< double > GetTimesSummary() const
SatResult CheckRedundancy(int id, int idx)
Cube * p
Definition exorList.c:222
Definition rrr.h:16
std::vector< std::pair< std::string, T > > summary
Definition rrrTypes.h:66
@ UNDEF
Definition rrrTypes.h:25
@ TEMP_FALSE
Definition rrrTypes.h:29
@ TRUE
Definition rrrTypes.h:26
@ FALSE
Definition rrrTypes.h:27
@ TEMP_TRUE
Definition rrrTypes.h:28
@ POP_BACK
Definition rrrTypes.h:45
@ REMOVE_BUFFER
Definition rrrTypes.h:36
@ REMOVE_UNUSED
Definition rrrTypes.h:35
@ TRIVIAL_DECOMPOSE
Definition rrrTypes.h:40
@ TRIVIAL_COLLAPSE
Definition rrrTypes.h:39
@ SAVE
Definition rrrTypes.h:43
@ REMOVE_CONST
Definition rrrTypes.h:37
@ LOAD
Definition rrrTypes.h:44
@ SORT_FANINS
Definition rrrTypes.h:41
@ REMOVE_FANIN
Definition rrrTypes.h:34
@ ADD_FANIN
Definition rrrTypes.h:38
@ READ
Definition rrrTypes.h:42
std::chrono::time_point< clock_type > time_point
Definition rrrTypes.h:63
SatResult
Definition rrrTypes.h:18
@ SAT
Definition rrrTypes.h:19
@ UNDET
Definition rrrTypes.h:21
@ UNSAT
Definition rrrTypes.h:20
@ AND
Definition rrrTypes.h:13
#define false
Definition place_base.h:29
sat_solver * sat_solver_new(void)
Definition satSolver.c:1137
void sat_solver_restart(sat_solver *s)
Definition satSolver.c:1389
void sat_solver_setnvars(sat_solver *s, int n)
Definition satSolver.c:1272
void sat_solver_delete(sat_solver *s)
Definition satSolver.c:1341
ActionType type
Definition rrrTypes.h:50
#define assert(ex)
Definition util_old.h:213