1 /*
2 * This file is part of the Yices SMT Solver.
3 * Copyright (C) 2017 SRI International.
4 *
5 * Yices is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Yices is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Yices. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * ENCODING OF BOOLEAN OPERATORS IN CLAUSAL FORM
21 */
22
23
24 #include <stdint.h>
25 #include <assert.h>
26
27 #include "solvers/cdcl/gates_manager.h"
28 #include "utils/int_array_sort.h"
29
30 /*
31 * Initialize manager m
32 * - core = attached core solver
33 */
init_gate_manager(gate_manager_t * m,smt_core_t * core)34 void init_gate_manager(gate_manager_t *m, smt_core_t *core) {
35 m->core = core;
36 m->htbl = get_gate_table(core);
37 init_ivector(&m->buffer, 0);
38 }
39
40
41 /*
42 * Delete hash table and buffer
43 */
delete_gate_manager(gate_manager_t * m)44 void delete_gate_manager(gate_manager_t *m) {
45 m->core = NULL;
46 m->htbl = NULL;
47 delete_ivector(&m->buffer);
48 }
49
50
51
52 /**********************
53 * OR AND AND GATES *
54 *********************/
55
56 /*
57 * Assert clauses for l == (OR a[0] ... a[n-1])
58 * - the literals a[0] ... a[n-1] are stored in vector v
59 * - v is modified
60 */
assert_ordef_clauses(smt_core_t * s,literal_t l,ivector_t * v)61 static void assert_ordef_clauses(smt_core_t *s, literal_t l, ivector_t *v) {
62 uint32_t i, n;
63
64 n = v->size;
65 for (i=0; i<n; i++) {
66 add_binary_clause(s, l, not(v->data[i]));
67 }
68
69 ivector_push(v, not(l));
70 add_clause(s, n+1, v->data);
71 }
72
73
74 /*
75 * Construct OR based on the content of vector v
76 * - v should not contain false literals (or true literals)
77 * - tbl = gate table
78 * - s = smt core
79 */
aux_or_constructor(gate_table_t * tbl,smt_core_t * s,ivector_t * v)80 static literal_t aux_or_constructor(gate_table_t *tbl, smt_core_t *s, ivector_t *v) {
81 uint32_t i, n, p;
82 literal_t aux, l;
83 literal_t *a;
84 boolgate_t *g;
85
86 n = v->size;
87 a = v->data;
88
89 if (n == 0) return false_literal;
90
91 /*
92 * Sort, remove duplicates, check for complementary literals
93 */
94 int_array_sort(a, n);
95 l = a[0];
96 p = 1;
97 for (i=1; i<n; i++) {
98 aux = a[i];
99 if (aux != l) {
100 if (aux == not(l)) return true_literal; // (or .. l not(l) ..)
101 a[p++] = aux;
102 l = aux;
103 }
104 }
105
106 if (p == 1) return a[0];
107 ivector_shrink(v, p);
108
109 if (p <= MAX_HASHCONS_SIZE) {
110 // hash-consing
111 g = gate_table_get(tbl, orgate_tag(p), a);
112 l = g->lit[p]; // output literal for an or-gate
113 if (l == null_literal) {
114 // new gate: create a fresh literal l
115 l = pos_lit(create_boolean_variable(s));
116 g->lit[p] = l;
117 assert_ordef_clauses(s, l, v);
118 }
119
120 } else {
121 // no hash-consing
122 l = pos_lit(create_boolean_variable(s));
123 assert_ordef_clauses(s, l, v);
124 }
125
126 return l;
127 }
128
129
130 /*
131 * OR GATE
132 */
mk_or_gate(gate_manager_t * m,uint32_t n,literal_t * a)133 literal_t mk_or_gate(gate_manager_t *m, uint32_t n, literal_t *a) {
134 smt_core_t *s;
135 ivector_t *v;
136 literal_t l;
137 uint32_t i;
138
139 s = m->core;
140 v = &m->buffer;
141 ivector_reset(v);
142
143 /*
144 * Remove false literals/check for true literals
145 * - copy unassigned literals in the buffer
146 */
147 for (i = 0; i<n; i++) {
148 l = a[i];
149 switch (literal_base_value(s, l)) {
150 case VAL_FALSE:
151 break;
152 case VAL_UNDEF_FALSE:
153 case VAL_UNDEF_TRUE:
154 ivector_push(v, l);
155 break;
156 case VAL_TRUE:
157 return true_literal;
158 }
159 }
160
161 return aux_or_constructor(m->htbl, s, v);
162 }
163
mk_or_gate2(gate_manager_t * m,literal_t l1,literal_t l2)164 literal_t mk_or_gate2(gate_manager_t *m, literal_t l1, literal_t l2) {
165 literal_t a[2];
166
167 a[0] = l1;
168 a[1] = l2;
169 return mk_or_gate(m, 2, a);
170 }
171
mk_or_gate3(gate_manager_t * m,literal_t l1,literal_t l2,literal_t l3)172 literal_t mk_or_gate3(gate_manager_t *m, literal_t l1, literal_t l2, literal_t l3) {
173 literal_t a[3];
174
175 a[0] = l1;
176 a[1] = l2;
177 a[2] = l3;
178 return mk_or_gate(m, 3, a);
179 }
180
181
182
183
184
185 /*
186 * AND GATE
187 */
mk_and_gate(gate_manager_t * m,uint32_t n,literal_t * a)188 literal_t mk_and_gate(gate_manager_t *m, uint32_t n, literal_t *a) {
189 smt_core_t *s;
190 ivector_t *v;
191 literal_t l;
192 uint32_t i;
193
194 s = m->core;
195 v = &m->buffer;
196 ivector_reset(v);
197
198 /*
199 * Remove true literals/check for false literals
200 * - copy negation of unassigned literals in the buffer
201 */
202 for (i = 0; i<n; i++) {
203 l = a[i];
204 switch (literal_base_value(s, l)) {
205 case VAL_FALSE:
206 return false_literal;
207 case VAL_UNDEF_FALSE:
208 case VAL_UNDEF_TRUE:
209 ivector_push(v, not(l));
210 break;
211 case VAL_TRUE:
212 break;
213 }
214 }
215
216 return not(aux_or_constructor(m->htbl, s, v));
217 }
218
219
mk_and_gate2(gate_manager_t * m,literal_t l1,literal_t l2)220 literal_t mk_and_gate2(gate_manager_t *m, literal_t l1, literal_t l2) {
221 literal_t a[2];
222
223 a[0] = l1;
224 a[1] = l2;
225 return mk_and_gate(m, 2, a);
226 }
227
mk_and_gate3(gate_manager_t * m,literal_t l1,literal_t l2,literal_t l3)228 literal_t mk_and_gate3(gate_manager_t *m, literal_t l1, literal_t l2, literal_t l3) {
229 literal_t a[3];
230
231 a[0] = l1;
232 a[1] = l2;
233 a[2] = l3;
234 return mk_and_gate(m, 3, a);
235 }
236
237
238
239
240 /***************
241 * XOR GATES *
242 **************/
243
244 /*
245 * Create a literal l and assert clauses equivalent to l=(xor l1 l2)
246 */
assert_xordef2(smt_core_t * s,literal_t l1,literal_t l2)247 static literal_t assert_xordef2(smt_core_t *s, literal_t l1, literal_t l2) {
248 literal_t l;
249
250 l = pos_lit(create_boolean_variable(s));
251 add_ternary_clause(s, not(l1), not(l2), not(l));
252 add_ternary_clause(s, not(l1), l2, l);
253 add_ternary_clause(s, l1, not(l2), l);
254 add_ternary_clause(s, l1, l2, not(l));
255
256 // EXPERIMENTAL
257 // if (s->etable != NULL) {
258 // smt_core_record_xor_def(s, l, l1, l2);
259 // }
260
261 return l;
262 }
263
264 /*
265 * Create a literal l and assert clauses for l = (xor a[0] ... a[n-1])
266 * - v = vector a[0] ... a[n-1]
267 * - assumptions: v contains not false or true literals, no duplicate,
268 * and no pairs of complementary literals
269 * - n must be positive
270 */
assert_xordef_clauses(smt_core_t * s,ivector_t * v)271 static literal_t assert_xordef_clauses(smt_core_t *s, ivector_t *v) {
272 uint32_t i, n;
273 literal_t *a;
274 literal_t l;
275
276 n = v->size;
277 a = v->data;
278
279 assert(n > 0);
280
281 l = a[0];
282 for (i=1; i<n; i++) {
283 l = assert_xordef2(s, l, a[i]);
284 }
285 return l;
286 }
287
288 /*
289 * Simplify (XOR a[0] ... a[n-1])
290 * - the result is given by vector v and the returned integer
291 * - the returned value is either 0 or 1
292 * - if it's 0 the result is (XOR v[0] ... v[p-1])
293 * - if it's 1 the result is not (XOR v[0] ... v[p-1])
294 *
295 * HACK: the simplifications use bit-tricks that are dependent
296 * on the literal representation, namely,
297 * low-order bit = 0 for positive literals
298 * low-order bit = 1 for negative literals
299 */
simplify_xor(smt_core_t * s,uint32_t n,literal_t * a,ivector_t * v)300 static uint32_t simplify_xor(smt_core_t *s, uint32_t n, literal_t *a, ivector_t *v) {
301 uint32_t i, sgn, p;
302 literal_t l;
303
304 ivector_reset(v);
305 sgn = 0;
306
307 // remove true/false literals and negative literals
308 for (i=0; i<n; i++) {
309 l = a[i];
310 switch (literal_base_value(s, l)) {
311 case VAL_FALSE:
312 break;
313 case VAL_UNDEF_FALSE:
314 case VAL_UNDEF_TRUE:
315 sgn ^= sign_of_lit(l); // flip sgn if l is negative
316 l &= ~1; // remove sign = low-order bit
317 ivector_push(v, l);
318 break;
319 case VAL_TRUE:
320 sgn ^= 1;
321 break;
322 }
323 }
324
325 a = v->data;
326 n = v->size;
327
328 if (n > 0) {
329 // remove duplicates (i.e., apply the rule (XOR x x) == 0)
330 int_array_sort(a, n);
331 p = 0;
332 i = 0;
333 while (i<n-1) {
334 l = a[i];
335 if (l == a[i+1]) {
336 i += 2;
337 } else {
338 a[p++] = l;
339 i ++;
340 }
341 }
342 if (i == n-1) {
343 a[p++] = a[i];
344 }
345 ivector_shrink(v, p);
346 }
347
348 return sgn;
349 }
350
351 /*
352 * Simplify then create l = (XOR a[0] ... a[n-1])
353 */
mk_xor_gate(gate_manager_t * m,uint32_t n,literal_t * a)354 literal_t mk_xor_gate(gate_manager_t *m, uint32_t n, literal_t *a) {
355 smt_core_t *s;
356 ivector_t *v;
357 literal_t l;
358 uint32_t sgn;
359 boolgate_t *g;
360
361 s = m->core;
362 v = &m->buffer;
363
364 sgn = simplify_xor(s, n, a, v);
365
366 a = v->data;
367 n = v->size;
368
369 if (n == 0) return false_literal ^ sgn;
370 if (n == 1) return a[0] ^ sgn;
371
372 if (n <= MAX_HASHCONS_SIZE) {
373 g = gate_table_get(m->htbl, xorgate_tag(n), a);
374 l = g->lit[n];
375 if (l == null_literal) {
376 l = assert_xordef_clauses(s, v);
377 g->lit[n] = l;
378 }
379 } else {
380 l = assert_xordef_clauses(s, v);
381 }
382
383 return l ^ sgn;
384 }
385
386
mk_xor_gate2(gate_manager_t * m,literal_t l1,literal_t l2)387 literal_t mk_xor_gate2(gate_manager_t *m, literal_t l1, literal_t l2) {
388 literal_t a[2];
389
390 a[0] = l1;
391 a[1] = l2;
392 return mk_xor_gate(m, 2, a);
393 }
394
mk_xor_gate3(gate_manager_t * m,literal_t l1,literal_t l2,literal_t l3)395 literal_t mk_xor_gate3(gate_manager_t *m, literal_t l1, literal_t l2, literal_t l3) {
396 literal_t a[3];
397
398 a[0] = l1;
399 a[1] = l2;
400 a[2] = l3;
401 return mk_xor_gate(m, 3, a);
402 }
403
404
405 /*
406 * Assert (XOR l1 l2)
407 */
assert_xor2_clauses(smt_core_t * s,literal_t l1,literal_t l2)408 static void assert_xor2_clauses(smt_core_t *s, literal_t l1, literal_t l2) {
409 add_binary_clause(s, l1, l2);
410 add_binary_clause(s, not(l1), not(l2));
411 }
412
413 /*
414 * Assert (XOR l1 l2 l3) == true
415 */
assert_xor3_clauses(smt_core_t * s,literal_t l1,literal_t l2,literal_t l3)416 static void assert_xor3_clauses(smt_core_t *s, literal_t l1, literal_t l2, literal_t l3) {
417 add_ternary_clause(s, l1, l2, l3);
418 add_ternary_clause(s, l1, not(l2), not(l3));
419 add_ternary_clause(s, not(l1), l2, not(l3));
420 add_ternary_clause(s, not(l1), not(l2), l3);
421 }
422
423
424 /*
425 * Assertion of (XOR a[0] ... a[n-1]) == true/false
426 */
assert_xor(gate_manager_t * m,uint32_t n,literal_t * a,bool val)427 void assert_xor(gate_manager_t *m, uint32_t n, literal_t *a, bool val) {
428 smt_core_t *s;
429 ivector_t *v;
430 uint32_t i, sgn;
431 literal_t l;
432
433 s = m->core;
434 v = &m->buffer;
435 sgn = simplify_xor(s, n, a, v);
436 a = v->data;
437 n = v->size;
438
439 if (sgn == 1) {
440 val = ! val;
441 }
442
443 if (n == 0) {
444 // empty (XOR ..) is false_literal
445 if (val) add_empty_clause(s);
446 return;
447 }
448
449 // (not (XOR a[0] ... a[n-1])) <=> (XOR (not a[0]) ... a[n-1])
450 if (! val) {
451 a[0] = not(a[0]);
452 }
453
454 if (n == 1) {
455 add_unit_clause(s, a[0]);
456 } else if (n == 2) {
457 assert_xor2_clauses(s, a[0], a[1]);
458 } else {
459 l = a[2];
460 for (i=3; i<n; i++) {
461 l = assert_xordef2(s, l, a[i]);
462 }
463 assert_xor3_clauses(s, a[0], a[1], l);
464 }
465
466 }
467
assert_xor2(gate_manager_t * m,literal_t l1,literal_t l2,bool val)468 void assert_xor2(gate_manager_t *m, literal_t l1, literal_t l2, bool val) {
469 literal_t a[2];
470
471 a[0] = l1;
472 a[1] = l2;
473 assert_xor(m, 2, a, val);
474 }
475
assert_xor3(gate_manager_t * m,literal_t l1,literal_t l2,literal_t l3,bool val)476 void assert_xor3(gate_manager_t *m, literal_t l1, literal_t l2, literal_t l3, bool val) {
477 literal_t a[3];
478
479 a[0] = l1;
480 a[1] = l2;
481 a[2] = l3;
482 assert_xor(m, 3, a, val);
483 }
484
485
486
487 /************************
488 * BOOLEAN IF-THEN-ELSE *
489 ***********************/
490
491 /*
492 * Construct l = (ite c l1 l2) (or find it in the gate table)
493 */
mk_ite_aux(gate_manager_t * m,literal_t c,literal_t l1,literal_t l2)494 static literal_t mk_ite_aux(gate_manager_t *m, literal_t c, literal_t l1, literal_t l2) {
495 smt_core_t *s;
496 boolgate_t *g;
497 literal_t a[3], l;
498
499 a[0] = c;
500 a[1] = l1;
501 a[2] = l2;
502 g = gate_table_get(m->htbl, itegate_tag(), a);
503 l = g->lit[3];
504 if (l == null_literal) {
505 s = m->core;
506 l = pos_lit(create_boolean_variable(s));
507 g->lit[3] = l;
508 add_ternary_clause(s, not(l), c, l2);
509 add_ternary_clause(s, not(l), not(c), l1);
510 add_ternary_clause(s, l, c, not(l2));
511 add_ternary_clause(s, l, not(c), not(l1));
512
513 /*
514 * Redundant clauses that may help propagation:
515 * (l1 and l2 ==> l)
516 * (not l1 and not l2 ==> not l)
517 */
518 #if 0
519 add_ternary_clause(s, not(l1), not(l2), l);
520 add_ternary_clause(s, l1, l2, not(l));
521 #endif
522 }
523 return l;
524 }
525
526
527 /*
528 * Normalize: make sure c and l are positive literals in (ite c l1 l2)
529 * Rules:
530 * (ite (not c) l1 l2) --> (ite c l2 l1)
531 * (ite c (not l1) l2) --> (not (ite c l1 (not l2)))
532 */
mk_ite_aux2(gate_manager_t * m,literal_t c,literal_t l1,literal_t l2)533 static literal_t mk_ite_aux2(gate_manager_t *m, literal_t c, literal_t l1, literal_t l2) {
534 literal_t aux;
535
536 if (is_neg(c)) {
537 c = not(c);
538 aux = l1; l1 = l2; l2 = aux; // swap l1 and l2
539 }
540
541 if (is_neg(l1)) {
542 return not(mk_ite_aux(m, c, not(l1), not(l2)));
543 } else {
544 return mk_ite_aux(m, c, l1, l2);
545 }
546 }
547
548
549 /*
550 * Simplify then generate l = (ite c l1 l2)
551 */
mk_ite_gate(gate_manager_t * m,literal_t c,literal_t l1,literal_t l2)552 literal_t mk_ite_gate(gate_manager_t *m, literal_t c, literal_t l1, literal_t l2) {
553 smt_core_t *s;
554 bval_t v1, v2;
555
556 s = m->core;
557
558 switch (literal_base_value(s, c)) {
559 case VAL_FALSE:
560 return l2;
561 case VAL_UNDEF_FALSE:
562 case VAL_UNDEF_TRUE:
563 /*
564 * (ite c l l) == l
565 * (ite c l (not l)) == (iff c l) --> CHECK THIS: not clear that it helps
566 *
567 * (ite c c l2) == (ite c true l2) == (or c l2)
568 * (ite c l1 c) == (ite c l1 false) == (and c l1)
569 * (ite c (not c) l2) == (ite c false l2) == (and (not c) l2)
570 * (ite c l1 (not c)) == (ite c l1 true) == (or (not c) l1)
571 */
572 if (l1 == l2) return l1;
573 if (opposite(l1, l2)) return mk_iff_gate(m, c, l1);
574
575 v1 = literal_base_value(s, l1);
576 v2 = literal_base_value(s, l2);
577 if (c == l1 || v1 == VAL_TRUE) return mk_or_gate2(m, c, l2);
578 if (c == l2 || v2 == VAL_FALSE) return mk_and_gate2(m, c, l1);
579 if (c == not(l1) || v1 == VAL_FALSE) return mk_and_gate2(m, not(c), l2);
580 if (c == not(l2) || v2 == VAL_TRUE) return mk_or_gate2(m, not(c), l1);
581
582 return mk_ite_aux2(m, c, l1, l2);
583
584 case VAL_TRUE:
585 default: // prevents compilation warning
586 return l1;
587 }
588 }
589
590
591 /*
592 * Assert (ite c l1 l2) == val
593 * - val is true or false
594 */
assert_ite(gate_manager_t * m,literal_t c,literal_t l1,literal_t l2,bool val)595 void assert_ite(gate_manager_t *m, literal_t c, literal_t l1, literal_t l2, bool val) {
596 smt_core_t *s;
597 bval_t v1, v2;
598
599 if (! val) {
600 l1 = not(l1);
601 l2 = not(l2);
602 }
603
604 s = m->core;
605
606 if (l1 == l2) {
607 add_unit_clause(s, l1);
608 } else {
609 /*
610 * We need two clauses: (or (not c) l1) and (or c l2)
611 * It's marginally better to simplify them here than let
612 * smt_core do it (because we avoid unit propagation).
613 */
614 switch (literal_base_value(s, c)) {
615 case VAL_FALSE:
616 add_unit_clause(s, l2);
617 break;
618
619 case VAL_UNDEF_FALSE:
620 case VAL_UNDEF_TRUE:
621 v1 = literal_base_value(s, l1);
622 v2 = literal_base_value(s, l2);
623 if (c == l1 || v1 == VAL_TRUE) {
624 add_binary_clause(s, c, l2); // assert (or c l2)
625 break;
626 }
627 if (c == l2 || v2 == VAL_FALSE) {
628 add_unit_clause(s, c);
629 add_unit_clause(s, l1); // assert (and c l1)
630 break;
631 }
632 if (c == not(l1) || v1 == VAL_FALSE) {
633 add_unit_clause(s, not(c));
634 add_unit_clause(s, l2); // assert (and (not c) l2)
635 break;
636 }
637 if (c == not(l2) || v2 == VAL_TRUE) {
638 add_binary_clause(s, not(c), l1); // assert (or (not c) l1)
639 break;
640 }
641
642 add_binary_clause(s, not(c), l1);
643 add_binary_clause(s, c, l2);
644 #if 0
645 // redundant clause that may help ?
646 add_binary_clause(s, l1, l2);
647 #endif
648 break;
649
650 case VAL_TRUE:
651 add_unit_clause(s, l1);
652 break;
653 }
654 }
655 }
656