ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_gates.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "internal.hpp"
4
6
7namespace CaDiCaL {
8
9/*------------------------------------------------------------------------*/
10
11// As in our original SATeLite published at SAT'05 we are trying to find
12// gates in order to restrict the number of resolutions that need to be
13// tried. If there is such a gate, we only need to consider resolvents
14// among gate and one non-gate clauses. Resolvents between definitions will
15// be tautological anyhow and resolvents among non-gates can actually be
16// shown to be redundant too.
17
18/*------------------------------------------------------------------------*/
19
20// The next function returns a non-zero if the clause 'c', which is assumed
21// to contain the literal 'first', after removing falsified literals is a
22// binary clause. Then the actual second literal is returned.
23
25 Clause *c, int first) {
27 int second = 0;
28 for (const auto &lit : *c) {
29 if (lit == first)
30 continue;
31 const signed char tmp = val (lit);
32 if (tmp < 0)
33 continue;
34 if (tmp > 0) {
35 mark_garbage (c);
36 elim_update_removed_clause (eliminator, c);
37 return 0;
38 }
39 if (second) {
40 second = INT_MIN;
41 break;
42 }
43 second = lit;
44 }
45 if (!second)
46 return 0;
47 if (second == INT_MIN)
48 return 0;
49 CADICAL_assert (active (second));
50#ifdef LOGGING
51 if (c->size == 2)
52 LOG (c, "found binary");
53 else
54 LOG (c, "found actual binary %d %d", first, second);
55#endif
56 return second;
57}
58
59/*------------------------------------------------------------------------*/
60
61// need a copy from above that does not care about garbage
62
64 if (c->garbage)
65 return 0;
66 int second = 0;
67 for (const auto &lit : *c) {
68 if (lit == first)
69 continue;
70 const signed char tmp = val (lit);
71 if (tmp < 0)
72 continue;
73 if (tmp > 0)
74 return 0;
75 if (!tmp) {
76 if (second) {
77 second = INT_MIN;
78 break;
79 }
80 second = lit;
81 }
82 }
83 if (!second)
84 return 0;
85 if (second == INT_MIN)
86 return 0;
87 return second;
88}
89
90// I needed to find the second clause for hyper unary resolution to build
91// LRAT this is not efficient but I could not find a better way then just
92// finding the corresponding clause in all possible clauses
93//
94Clause *Internal::find_binary_clause (int first, int second) {
95 int best = first;
96 int other = second;
97 if (occs (first).size () > occs (second).size ()) {
98 best = second;
99 other = first;
100 }
101 for (auto c : occs (best))
102 if (second_literal_in_binary_clause_lrat (c, best) == other)
103 return c;
104 return 0;
105}
106
107/*------------------------------------------------------------------------*/
108
109// Mark all other literals in binary clauses with 'first'. During this
110// marking we might also detect hyper unary resolvents producing a unit.
111// If such a unit is found we propagate it and return immediately.
112
113void Internal::mark_binary_literals (Eliminator &eliminator, int first) {
114
115 if (unsat)
116 return;
117 if (val (first))
118 return;
119 if (!eliminator.gates.empty ())
120 return;
121
122 CADICAL_assert (!marked (first));
123 CADICAL_assert (eliminator.marked.empty ());
124
125 const Occs &os = occs (first);
126 for (const auto &c : os) {
127 if (c->garbage)
128 continue;
129 const int second =
130 second_literal_in_binary_clause (eliminator, c, first);
131 if (!second)
132 continue;
133 const int tmp = marked (second);
134 if (tmp < 0) {
135 // had a bug where units could occur multiple times here
136 // solved with flags
137 LOG ("found binary resolved unit %d", first);
138 if (lrat) {
139 Clause *d = find_binary_clause (first, -second);
140 CADICAL_assert (d);
141 for (auto &lit : *d) {
142 if (lit == first || lit == -second)
143 continue;
144 CADICAL_assert (val (lit) < 0);
145 Flags &f = flags (lit);
146 if (f.seen)
147 continue;
148 analyzed.push_back (lit);
149 f.seen = true;
150 int64_t id = unit_id (-lit);
151 lrat_chain.push_back (id);
152 // LOG ("gates added id %" PRId64, id);
153 }
154 for (auto &lit : *c) {
155 if (lit == first || lit == second)
156 continue;
157 CADICAL_assert (val (lit) < 0);
158 Flags &f = flags (lit);
159 if (f.seen)
160 continue;
161 analyzed.push_back (lit);
162 f.seen = true;
163 int64_t id = unit_id (-lit);
164 lrat_chain.push_back (id);
165 // LOG ("gates added id %" PRId64, id);
166 }
167 lrat_chain.push_back (c->id);
168 lrat_chain.push_back (d->id);
169 // LOG ("gates added id %" PRId64, c->id);
170 // LOG ("gates added id %" PRId64, d->id);
172 }
173 assign_unit (first);
174 elim_propagate (eliminator, first);
175 return;
176 }
177 if (tmp > 0) {
178 LOG (c, "duplicated actual binary clause");
179 elim_update_removed_clause (eliminator, c);
180 mark_garbage (c);
181 continue;
182 }
183 eliminator.marked.push_back (second);
184 mark (second);
185 LOG ("marked second literal %d in binary clause %d %d", second, first,
186 second);
187 }
188}
189
190// Unmark all literals saved on the 'marked' stack.
191
193 LOG ("unmarking %zd literals", eliminator.marked.size ());
194 for (const auto &lit : eliminator.marked)
195 unmark (lit);
196 eliminator.marked.clear ();
197}
198
199/*------------------------------------------------------------------------*/
200
201// Find equivalence for 'pivot'. Requires that all other literals in binary
202// clauses with 'pivot' are marked (through 'mark_binary_literals');
203
204void Internal::find_equivalence (Eliminator &eliminator, int pivot) {
205
206 if (!opts.elimequivs)
207 return;
208
209 CADICAL_assert (opts.elimsubst);
210
211 if (unsat)
212 return;
213 if (val (pivot))
214 return;
215 if (!eliminator.gates.empty ())
216 return;
217
218 mark_binary_literals (eliminator, pivot);
219 if (unsat || val (pivot))
220 goto DONE;
221
222 for (const auto &c : occs (-pivot)) {
223
224 if (c->garbage)
225 continue;
226
227 const int second =
228 second_literal_in_binary_clause (eliminator, c, -pivot);
229 if (!second)
230 continue;
231 const int tmp = marked (second);
232 if (tmp > 0) {
233 LOG ("found binary resolved unit %d", second);
234 // did not find a bug where units could occur multiple times here
235 // still solved potential issues with flags
236 if (lrat) {
237 Clause *d = find_binary_clause (pivot, second);
238 CADICAL_assert (d);
239 for (auto &lit : *d) {
240 if (lit == pivot || lit == second)
241 continue;
242 CADICAL_assert (val (lit) < 0);
243 Flags &f = flags (lit);
244 if (f.seen)
245 continue;
246 analyzed.push_back (lit);
247 f.seen = true;
248 int64_t id = unit_id (-lit);
249 lrat_chain.push_back (id);
250 // LOG ("gates added id %" PRId64, id);
251 }
252 for (auto &lit : *c) {
253 if (lit == -pivot || lit == second)
254 continue;
255 CADICAL_assert (val (lit) < 0);
256 Flags &f = flags (lit);
257 if (f.seen)
258 continue;
259 analyzed.push_back (lit);
260 f.seen = true;
261 int64_t id = unit_id (-lit);
262 lrat_chain.push_back (id);
263 // LOG ("gates added id %" PRId64, id);
264 }
265 lrat_chain.push_back (c->id);
266 lrat_chain.push_back (d->id);
268 // LOG ("gates added id %" PRId64, c->id);
269 // LOG ("gates added id %" PRId64, d->id);
270 }
271 assign_unit (second);
272 elim_propagate (eliminator, second);
273 if (val (pivot))
274 break;
275 if (unsat)
276 break;
277 }
278 if (tmp >= 0)
279 continue;
280
281 LOG ("found equivalence %d = %d", pivot, -second);
282 stats.elimequivs++;
283 stats.elimgates++;
284
285 LOG (c, "first gate clause");
286 CADICAL_assert (!c->gate);
287 c->gate = true;
288 eliminator.gates.push_back (c);
289
290 Clause *d = 0;
291 const Occs &ps = occs (pivot);
292 for (const auto &e : ps) {
293 if (e->garbage)
294 continue;
295 const int other =
296 second_literal_in_binary_clause (eliminator, e, pivot);
297 if (other == -second) {
298 d = e;
299 break;
300 }
301 }
302 CADICAL_assert (d);
303
304 LOG (d, "second gate clause");
305 CADICAL_assert (!d->gate);
306 d->gate = true;
307 eliminator.gates.push_back (d);
308 eliminator.gatetype = EQUI;
309
310 break;
311 }
312
313DONE:
314 unmark_binary_literals (eliminator);
315}
316
317/*------------------------------------------------------------------------*/
318
319// Find and gates for 'pivot' with a long clause, in which the pivot occurs
320// positively. Requires that all other literals in binary clauses with
321// 'pivot' are marked (through 'mark_binary_literals');
322
323void Internal::find_and_gate (Eliminator &eliminator, int pivot) {
324
325 if (!opts.elimands)
326 return;
327
328 CADICAL_assert (opts.elimsubst);
329
330 if (unsat)
331 return;
332 if (val (pivot))
333 return;
334 if (!eliminator.gates.empty ())
335 return;
336
337 mark_binary_literals (eliminator, pivot);
338 if (unsat || val (pivot))
339 goto DONE;
340
341 for (const auto &c : occs (-pivot)) {
342
343 if (c->garbage)
344 continue;
345 if (c->size < 3)
346 continue;
347
348 bool all_literals_marked = true;
349 unsigned arity = 0;
350 int satisfied = 0;
351
352 for (const auto &lit : *c) {
353 if (lit == -pivot)
354 continue;
355 CADICAL_assert (lit != pivot);
356 signed char tmp = val (lit);
357 if (tmp < 0)
358 continue;
359 if (tmp > 0) {
360 satisfied = lit;
361 break;
362 }
363 tmp = marked (lit);
364 if (tmp < 0) {
365 arity++;
366 continue;
367 }
368 all_literals_marked = false;
369 break;
370 }
371
372 if (!all_literals_marked)
373 continue;
374
375 if (satisfied) {
376 LOG (c, "satisfied by %d candidate base clause", satisfied);
377 mark_garbage (c);
378 continue;
379 }
380
381#ifdef LOGGING
382 if (opts.log) {
383 Logger::print_log_prefix (this);
384 tout.magenta ();
385 printf ("found arity %u AND gate %d = ", arity, -pivot);
386 bool first = true;
387 for (const auto &lit : *c) {
388 if (lit == -pivot)
389 continue;
390 CADICAL_assert (lit != pivot);
391 if (!first)
392 fputs (" & ", stdout);
393 printf ("%d", -lit);
394 first = false;
395 }
396 fputc ('\n', stdout);
397 tout.normal ();
398 fflush (stdout);
399 }
400#endif
401 stats.elimands++;
402 stats.elimgates++;
403 eliminator.gatetype = AND;
404
405 (void) arity;
406 CADICAL_assert (!c->gate);
407 c->gate = true;
408 eliminator.gates.push_back (c);
409 for (const auto &lit : *c) {
410 if (lit == -pivot)
411 continue;
412 CADICAL_assert (lit != pivot);
413 signed char tmp = val (lit);
414 if (tmp < 0)
415 continue;
416 CADICAL_assert (!tmp);
417 CADICAL_assert (marked (lit) < 0);
418 marks[vidx (lit)] *= 2;
419 }
420
421 unsigned count = 0;
422 for (const auto &d : occs (pivot)) {
423 if (d->garbage)
424 continue;
425 const int other =
426 second_literal_in_binary_clause (eliminator, d, pivot);
427 if (!other)
428 continue;
429 const int tmp = marked (other);
430 if (tmp != 2)
431 continue;
432 LOG (d, "AND gate binary side clause");
433 CADICAL_assert (!d->gate);
434 d->gate = true;
435 eliminator.gates.push_back (d);
436 count++;
437 }
438 CADICAL_assert (count >= arity);
439 (void) count;
440
441 break;
442 }
443
444DONE:
445 unmark_binary_literals (eliminator);
446}
447
448/*------------------------------------------------------------------------*/
449
450// Find and extract ternary clauses.
451
452bool Internal::get_ternary_clause (Clause *d, int &a, int &b, int &c) {
453 if (d->garbage)
454 return false;
455 if (d->size < 3)
456 return false;
457 int found = 0;
458 a = b = c = 0;
459 for (const auto &lit : *d) {
460 if (val (lit))
461 continue;
462 if (++found == 1)
463 a = lit;
464 else if (found == 2)
465 b = lit;
466 else if (found == 3)
467 c = lit;
468 else
469 return false;
470 }
471 return found == 3;
472}
473
474// This function checks whether 'd' exists as ternary clause.
475
476bool Internal::match_ternary_clause (Clause *d, int a, int b, int c) {
477 if (d->garbage)
478 return false;
479 int found = 0;
480 for (const auto &lit : *d) {
481 if (val (lit))
482 continue;
483 if (a != lit && b != lit && c != lit)
484 return false;
485 found++;
486 }
487 return found == 3;
488}
489
490Clause *Internal::find_ternary_clause (int a, int b, int c) {
491 if (occs (b).size () > occs (c).size ())
492 swap (b, c);
493 if (occs (a).size () > occs (b).size ())
494 swap (a, b);
495 for (auto d : occs (a))
496 if (match_ternary_clause (d, a, b, c))
497 return d;
498 return 0;
499}
500
501/*------------------------------------------------------------------------*/
502
503// Find if-then-else gate.
504
505void Internal::find_if_then_else (Eliminator &eliminator, int pivot) {
506
507 if (!opts.elimites)
508 return;
509
510 CADICAL_assert (opts.elimsubst);
511
512 if (unsat)
513 return;
514 if (val (pivot))
515 return;
516 if (!eliminator.gates.empty ())
517 return;
518
519 const Occs &os = occs (pivot);
520 const auto end = os.end ();
521 for (auto i = os.begin (); i != end; i++) {
522 Clause *di = *i;
523 int ai, bi, ci;
524 if (!get_ternary_clause (di, ai, bi, ci))
525 continue;
526 if (bi == pivot)
527 swap (ai, bi);
528 if (ci == pivot)
529 swap (ai, ci);
530 CADICAL_assert (ai == pivot);
531 for (auto j = i + 1; j != end; j++) {
532 Clause *dj = *j;
533 int aj, bj, cj;
534 if (!get_ternary_clause (dj, aj, bj, cj))
535 continue;
536 if (bj == pivot)
537 swap (aj, bj);
538 if (cj == pivot)
539 swap (aj, cj);
540 CADICAL_assert (aj == pivot);
541 if (abs (bi) == abs (cj))
542 swap (bj, cj);
543 if (abs (ci) == abs (cj))
544 continue;
545 if (bi != -bj)
546 continue;
547 Clause *d1 = find_ternary_clause (-pivot, bi, -ci);
548 if (!d1)
549 continue;
550 Clause *d2 = find_ternary_clause (-pivot, bj, -cj);
551 if (!d2)
552 continue;
553 LOG (di, "1st if-then-else");
554 LOG (dj, "2nd if-then-else");
555 LOG (d1, "3rd if-then-else");
556 LOG (d2, "4th if-then-else");
557 LOG ("found ITE gate %d == (%d ? %d : %d)", pivot, -bi, -ci, -cj);
558 CADICAL_assert (!di->gate);
559 CADICAL_assert (!dj->gate);
560 CADICAL_assert (!d1->gate);
561 CADICAL_assert (!d2->gate);
562 di->gate = true;
563 dj->gate = true;
564 d1->gate = true;
565 d2->gate = true;
566 eliminator.gates.push_back (di);
567 eliminator.gates.push_back (dj);
568 eliminator.gates.push_back (d1);
569 eliminator.gates.push_back (d2);
570 stats.elimgates++;
571 stats.elimites++;
572 eliminator.gatetype = ITE;
573 return;
574 }
575 }
576}
577
578/*------------------------------------------------------------------------*/
579
580// Find and extract clause.
581
583 if (c->garbage)
584 return false;
585 l.clear ();
586 for (const auto &lit : *c) {
587 if (val (lit) < 0)
588 continue;
589 if (val (lit) > 0) {
590 l.clear ();
591 return false;
592 }
593 l.push_back (lit);
594 }
595 return true;
596}
597
598// Check whether 'c' contains only the literals in 'l'.
599
601 if (c->garbage)
602 return false;
603 int size = lits.size ();
604 if (c->size < size)
605 return false;
606 int found = 0;
607 for (const auto &lit : *c) {
608 if (val (lit) < 0)
609 continue;
610 if (val (lit) > 0)
611 return false;
612 const auto it = find (lits.begin (), lits.end (), lit);
613 if (it == lits.end ())
614 return false;
615 if (++found > size)
616 return false;
617 }
618 return found == size;
619}
620
622 int best = 0;
623 size_t len = 0;
624 for (const auto &lit : lits) {
625 size_t l = occs (lit).size ();
626 if (best && l >= len)
627 continue;
628 len = l, best = lit;
629 }
630 for (auto c : occs (best))
631 if (is_clause (c, lits))
632 return c;
633 return 0;
634}
635
636void Internal::find_xor_gate (Eliminator &eliminator, int pivot) {
637
638 if (!opts.elimxors)
639 return;
640
641 CADICAL_assert (opts.elimsubst);
642
643 if (unsat)
644 return;
645 if (val (pivot))
646 return;
647 if (!eliminator.gates.empty ())
648 return;
649
651
652 for (auto d : occs (pivot)) {
653
654 if (!get_clause (d, lits))
655 continue;
656
657 const int size = lits.size (); // clause size
658 const int arity = size - 1; // arity of XOR
659
660 if (size < 3)
661 continue;
662 if (arity > opts.elimxorlim)
663 continue;
664
665 CADICAL_assert (eliminator.gates.empty ());
666
667 unsigned needed = (1u << arity) - 1; // additional clauses
668 unsigned signs = 0; // literals to negate
669
670 do {
671 const unsigned prev = signs;
672 while (parity (++signs))
673 ;
674 for (int j = 0; j < size; j++) {
675 const unsigned bit = 1u << j;
676 int lit = lits[j];
677 if ((prev & bit) != (signs & bit))
678 lits[j] = lit = -lit;
679 }
680 Clause *e = find_clause (lits);
681 if (!e)
682 break;
683 eliminator.gates.push_back (e);
684 } while (--needed);
685
686 if (needed) {
687 eliminator.gates.clear ();
688 continue;
689 }
690
691 eliminator.gates.push_back (d);
692 CADICAL_assert (eliminator.gates.size () == (1u << arity));
693
694#ifdef LOGGING
695 if (opts.log) {
696 Logger::print_log_prefix (this);
697 tout.magenta ();
698 printf ("found arity %u XOR gate %d = ", arity, -pivot);
699 bool first = true;
700 for (const auto &lit : *d) {
701 if (lit == pivot)
702 continue;
703 CADICAL_assert (lit != -pivot);
704 if (!first)
705 fputs (" ^ ", stdout);
706 printf ("%d", lit);
707 first = false;
708 }
709 fputc ('\n', stdout);
710 tout.normal ();
711 fflush (stdout);
712 }
713#endif
714 stats.elimgates++;
715 stats.elimxors++;
716 const auto end = eliminator.gates.end ();
717 auto j = eliminator.gates.begin ();
718 for (auto i = j; i != end; i++) {
719 Clause *e = *i;
720 if (e->gate)
721 continue;
722 e->gate = true;
723 LOG (e, "contributing");
724 *j++ = e;
725 }
726 eliminator.gates.resize (j - eliminator.gates.begin ());
727 eliminator.gatetype = XOR;
728 break;
729 }
730}
731
732/*------------------------------------------------------------------------*/
733
734// Find a gate for 'pivot'. If such a gate is found, the gate clauses are
735// marked and pushed on the stack of gates. Further hyper unary resolution
736// might detect units, which are propagated. This might assign the pivot or
737// even produce the empty clause.
738
739void Internal::find_gate_clauses (Eliminator &eliminator, int pivot) {
740 if (!opts.elimsubst)
741 return;
742
743 if (unsat)
744 return;
745 if (val (pivot))
746 return;
747
748 CADICAL_assert (eliminator.gates.empty ());
749
750 find_equivalence (eliminator, pivot);
751 find_and_gate (eliminator, pivot);
752 find_and_gate (eliminator, -pivot);
753 find_if_then_else (eliminator, pivot);
754 find_xor_gate (eliminator, pivot);
755 find_definition (eliminator, pivot);
756}
757
759 LOG ("unmarking %zd gate clauses", eliminator.gates.size ());
760 for (const auto &c : eliminator.gates) {
761 CADICAL_assert (c->gate);
762 c->gate = false;
763 }
764 eliminator.gates.clear ();
765 eliminator.definition_unit = 0;
766}
767
768/*------------------------------------------------------------------------*/
769
770} // namespace CaDiCaL
771
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
@ DONE
Definition inflate.h:51
vector< Clause * > Occs
Definition occs.hpp:18
const char * flags()
bool parity(unsigned a)
Definition util.hpp:71
@ EQUI
Definition elim.hpp:31
@ ITE
Definition elim.hpp:31
@ AND
Definition elim.hpp:31
@ XOR
Definition elim.hpp:31
Terminal tout(stdout)
Definition terminal.hpp:97
int lit
Definition satVec.h:130
vector< int > marked
Definition elim.hpp:51
unsigned definition_unit
Definition elim.hpp:49
vector< Clause * > gates
Definition elim.hpp:48
GateType gatetype
Definition elim.hpp:52
bool get_clause(Clause *, vector< int > &)
Clause * find_binary_clause(int, int)
vector< int > analyzed
Definition internal.hpp:267
void mark_garbage(Clause *)
vector< int64_t > lrat_chain
Definition internal.hpp:210
int second_literal_in_binary_clause(Eliminator &, Clause *, int first)
int vidx(int lit) const
Definition internal.hpp:395
void unmark(int lit)
Definition internal.hpp:490
bool get_ternary_clause(Clause *, int &, int &, int &)
void find_if_then_else(Eliminator &, int pivot)
void find_equivalence(Eliminator &, int pivot)
void find_gate_clauses(Eliminator &, int pivot)
bool is_clause(Clause *, const vector< int > &)
const Sange lits
Definition internal.hpp:325
void find_and_gate(Eliminator &, int pivot)
Clause * find_clause(const vector< int > &)
signed char val(int lit) const
signed char marked(int lit) const
Definition internal.hpp:478
int64_t unit_id(int lit) const
Definition internal.hpp:434
void unmark_gate_clauses(Eliminator &)
void unmark_binary_literals(Eliminator &)
bool active(int lit)
Definition internal.hpp:360
void find_xor_gate(Eliminator &, int pivot)
void elim_update_removed_clause(Eliminator &, Clause *, int except=0)
vector< signed char > marks
Definition internal.hpp:222
void mark_binary_literals(Eliminator &, int pivot)
Occs & occs(int lit)
Definition internal.hpp:465
bool match_ternary_clause(Clause *, int, int, int)
Clause * find_ternary_clause(int, int, int)
int second_literal_in_binary_clause_lrat(Clause *, int first)
void elim_propagate(Eliminator &, int unit)
void find_definition(Eliminator &, int)
unsigned size
Definition vector.h:35
signed char mark
Definition value.h:8