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