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 * DPLL(T) CORE
21 */
22
23 #include <assert.h>
24 #include <stddef.h>
25 #include <float.h>
26
27 #include "solvers/cdcl/smt_core.h"
28 #include "utils/gcd.h"
29 #include "utils/int_array_sort.h"
30 #include "utils/int_hash_sets.h"
31 #include "utils/int_queues.h"
32 #include "utils/memalloc.h"
33
34
35 #define TRACE 0
36 #define DEBUG 0
37
38 #if DEBUG || TRACE
39
40 #include <stdio.h>
41 #include <inttypes.h>
42
43 extern void print_literal(FILE *f, literal_t l);
44 extern void print_bval(FILE *f, bval_t b);
45 extern void print_bvar(FILE *f, bvar_t x);
46
47 #endif
48
49
50 #if DEBUG
51
52 // All debugging functions are defined at the end of this file
53 static void check_heap_content(smt_core_t *s);
54 static void check_heap(smt_core_t *s);
55 static void check_propagation(smt_core_t *s);
56 static void check_marks(smt_core_t *s);
57 static void check_theory_conflict(smt_core_t *s, literal_t *a);
58 static void check_theory_explanation(smt_core_t *s, literal_t l);
59 static void check_watched_literals(smt_core_t *s, uint32_t n, literal_t *a);
60 static void check_lemma(smt_core_t *s, uint32_t n, literal_t *a);
61
62 #endif
63
64
65
66
67 /**********
68 * PRNG *
69 *********/
70
71 /*
72 * PARAMETERS FOR THE PSEUDO RANDOM NUMBER GENERATOR
73 *
74 * We use the same linear congruence as in prng.h,
75 * but we use a local implementation so that different
76 * solvers can use different seeds.
77 */
78
79 #define CORE_PRNG_MULTIPLIER 1664525
80 #define CORE_PRNG_CONSTANT 1013904223
81 #define CORE_PRNG_SEED 0xabcdef98
82
83
84 /*
85 * Return a 32bit unsigned int
86 */
random_uint32(smt_core_t * s)87 static inline uint32_t random_uint32(smt_core_t *s) {
88 uint32_t x;
89
90 x = s->prng;
91 s->prng = x * ((uint32_t) CORE_PRNG_MULTIPLIER) + ((uint32_t) CORE_PRNG_CONSTANT);
92 return x;
93 }
94
95
96 /*
97 * Return a 32bit integer between 0 and n-1
98 */
random_uint(smt_core_t * s,uint32_t n)99 static inline uint32_t random_uint(smt_core_t *s, uint32_t n) {
100 return (random_uint32(s) >> 8) % n;
101 }
102
103
104
105
106 /********************************
107 * CLAUSES AND LEARNED CLAUSES *
108 *******************************/
109
110 /*
111 * Get first watched literal of cl
112 */
get_first_watch(clause_t * cl)113 static inline literal_t get_first_watch(clause_t *cl) {
114 return cl->cl[0];
115 }
116
117 /*
118 * Get second watched literal of cl
119 */
get_second_watch(clause_t * cl)120 static inline literal_t get_second_watch(clause_t *cl) {
121 return cl->cl[1];
122 }
123
124 /*
125 * Get watched literal of index (1 - i) in cl.
126 * - i = 0 or 1
127 */
get_other_watch(clause_t * cl,uint32_t i)128 static inline literal_t get_other_watch(clause_t *cl, uint32_t i) {
129 // flip low-order bit of i
130 return cl->cl[1 - i];
131 }
132
133 /*
134 * Get pointer to learned_clause in which clause cl is embedded.
135 */
learned(const clause_t * cl)136 static inline learned_clause_t *learned(const clause_t *cl) {
137 return (learned_clause_t *)(((char *)cl) - offsetof(learned_clause_t, clause));
138 }
139
140 /*
141 * Activity of a learned clause
142 */
get_activity(const clause_t * cl)143 static inline float get_activity(const clause_t *cl) {
144 return learned(cl)->activity;
145 }
146
147 /*
148 * Increase the activity of a learned clause by delta
149 */
increase_activity(clause_t * cl,float delta)150 static inline void increase_activity(clause_t *cl, float delta) {
151 learned(cl)->activity += delta;
152 }
153
154 /*
155 * Multiply activity by scale
156 */
multiply_activity(clause_t * cl,float scale)157 static inline void multiply_activity(clause_t *cl, float scale) {
158 learned(cl)->activity *= scale;
159 }
160
161 /*
162 * Mark a clause cl for removal
163 */
mark_for_removal(clause_t * cl)164 static inline void mark_for_removal(clause_t *cl) {
165 cl->cl[0] = - cl->cl[0];
166 cl->cl[1] = - cl->cl[1];
167 }
168
is_clause_to_be_removed(clause_t * cl)169 static inline bool is_clause_to_be_removed(clause_t *cl) {
170 return cl->cl[0] < 0;
171 }
172
173 /*
174 * Restore a removed clause: flip the signs back
175 */
restore_removed_clause(clause_t * cl)176 static inline void restore_removed_clause(clause_t *cl) {
177 cl->cl[0] = - cl->cl[0];
178 cl->cl[1] = - cl->cl[1];
179 }
180
181
182 /*
183 * Clause length
184 */
clause_length(clause_t * cl)185 static uint32_t clause_length(clause_t *cl) {
186 literal_t *a;
187
188 a = cl->cl + 2;
189 while (*a >= 0) {
190 a ++;
191 }
192
193 return a - cl->cl;
194 }
195
196 /*
197 * Allocate and initialize a new clause (not a learned clause)
198 * \param len = number of literals
199 * \param lit = array of len literals
200 * The watched pointers are not initialized
201 */
new_clause(uint32_t len,literal_t * lit)202 static clause_t *new_clause(uint32_t len, literal_t *lit) {
203 clause_t *result;
204 uint32_t i;
205
206 result = (clause_t *) safe_malloc(sizeof(clause_t) + sizeof(literal_t) +
207 len * sizeof(literal_t));
208
209 for (i=0; i<len; i++) {
210 result->cl[i] = lit[i];
211 }
212 result->cl[i] = end_clause; // end marker: not a learned clause
213
214 return result;
215 }
216
217 /*
218 * Delete clause cl
219 * cl must be a non-learned clause, allocated via the previous function.
220 */
delete_clause(clause_t * cl)221 static inline void delete_clause(clause_t *cl) {
222 safe_free(cl);
223 }
224
225 /*
226 * Allocate and initialize a new learned clause
227 * \param len = number of literals
228 * \param lit = array of len literals
229 * The watched pointers are not initialized.
230 * The activity is initialized to 0.0
231 */
new_learned_clause(uint32_t len,literal_t * lit)232 static clause_t *new_learned_clause(uint32_t len, literal_t *lit) {
233 learned_clause_t *tmp;
234 clause_t *result;
235 uint32_t i;
236
237 tmp = (learned_clause_t *) safe_malloc(sizeof(learned_clause_t) + sizeof(literal_t) +
238 len * sizeof(literal_t));
239 tmp->activity = 0.0;
240 result = &(tmp->clause);
241
242 for (i=0; i<len; i++) {
243 result->cl[i] = lit[i];
244 }
245 result->cl[i] = end_learned; // end marker: learned clause
246
247 return result;
248 }
249
250 /*
251 * Delete learned clause cl
252 * cl must have been allocated via the new_learned_clause function
253 */
delete_learned_clause(clause_t * cl)254 static inline void delete_learned_clause(clause_t *cl) {
255 safe_free(learned(cl));
256 }
257
258
259
260 /********************
261 * CLAUSE VECTORS *
262 *******************/
263
264 /*
265 * Create a clause vector of capacity n.
266 */
new_clause_vector(uint32_t n)267 static clause_t **new_clause_vector(uint32_t n) {
268 clause_vector_t *tmp;
269
270 tmp = (clause_vector_t *) safe_malloc(sizeof(clause_vector_t) + n * sizeof(clause_t *));
271 tmp->capacity = n;
272 tmp->size = 0;
273
274 return tmp->data;
275 }
276
277 /*
278 * Clean up: free memory used by v
279 */
delete_clause_vector(clause_t ** v)280 static void delete_clause_vector(clause_t **v) {
281 safe_free(cv_header(v));
282 }
283
284 /*
285 * Add clause cl at the end of vector *v. Assumes *v has been initialized.
286 */
add_clause_to_vector(clause_t *** v,clause_t * cl)287 static void add_clause_to_vector(clause_t ***v, clause_t *cl) {
288 clause_vector_t *vector;
289 clause_t **d;
290 uint32_t i, n;
291
292 d = *v;
293 vector = cv_header(d);
294 i = vector->size;
295 if (i == vector->capacity) {
296 n = i + 1;
297 n += (n >> 1); // n = new capacity
298 if (n > MAX_CLAUSE_VECTOR_SIZE) {
299 out_of_memory();
300 }
301 vector = (clause_vector_t *)
302 safe_realloc(vector, sizeof(clause_vector_t) + n * sizeof(clause_t *));
303 vector->capacity = n;
304 d = vector->data;
305 *v = d;
306 }
307 d[i] = cl;
308 vector->size = i+1;
309 }
310
311
312 /*
313 * Reset clause vector v: set its size to 0
314 */
reset_clause_vector(clause_t ** v)315 static inline void reset_clause_vector(clause_t **v) {
316 set_cv_size(v, 0);
317 }
318
319
320
321
322 /**********************
323 * LITERAL VECTORS *
324 *********************/
325
326 /*
327 * When used to store binary clauses literal vectors are initially
328 * NULL. Memory is allocated on the first addition and literal
329 * vectors are terminated by -1.
330 *
331 * For a vector v of size i, the literals are stored
332 * in v[0],...,v[i-1], and v[i] = -1
333 */
334
335 /*
336 * Add literal l at the end of vector *v
337 * - allocate a fresh vector if *v == NULL
338 * - resize *v if *v is full.
339 * - add -1 terminator after l.
340 */
add_literal_to_vector(literal_t ** v,literal_t l)341 static void add_literal_to_vector(literal_t **v, literal_t l) {
342 literal_vector_t *vector;
343 literal_t *d;
344 uint32_t i, n;
345
346 d = *v;
347 if (d == NULL) {
348 i = 0;
349 n = DEF_LITERAL_VECTOR_SIZE;
350 vector = (literal_vector_t *)
351 safe_malloc(sizeof(literal_vector_t) + n * sizeof(literal_t));
352 vector->capacity = n;
353 d = vector->data;
354 *v = d;
355 } else {
356 vector = lv_header(d);
357 i = vector->size;
358 n = vector->capacity;
359 if (i >= n - 1) {
360 n ++;
361 n += n>>1; // new cap = 50% more than old capacity
362 if (n > MAX_LITERAL_VECTOR_SIZE) {
363 out_of_memory();
364 }
365 vector = (literal_vector_t *)
366 safe_realloc(vector, sizeof(literal_vector_t) + n * sizeof(literal_t));
367 vector->capacity = n;
368 d = vector->data;
369 *v = d;
370 }
371 }
372
373 assert(i + 1 < vector->capacity);
374
375 d[i] = l;
376 d[i+1] = null_literal;
377 vector->size = i+1;
378 }
379
380
381 /*
382 * Delete literal vector v
383 */
delete_literal_vector(literal_t * v)384 static void delete_literal_vector(literal_t *v) {
385 if (v != NULL) {
386 safe_free(lv_header(v));
387 }
388 }
389
390
391 /*
392 * Remove the last literal from vector v
393 */
literal_vector_pop(literal_t * v)394 static void literal_vector_pop(literal_t *v) {
395 uint32_t i;
396
397 i = get_lv_size(v);
398 assert(i > 0);
399 i --;
400 v[i] = null_literal;
401 set_lv_size(v, i);
402 }
403
404
405 /*
406 * Last element of vector v (used in assert)
407 */
408 #ifndef NDEBUG
last_lv_elem(literal_t * v)409 static inline literal_t last_lv_elem(literal_t *v) {
410 assert(v != NULL && get_lv_size(v) > 0);
411 return v[get_lv_size(v) - 1];
412 }
413 #endif
414
415
416 /***********
417 * STACK *
418 **********/
419
420 /*
421 * Initialize stack s for nvar
422 */
init_stack(prop_stack_t * s,uint32_t nvar)423 static void init_stack(prop_stack_t *s, uint32_t nvar) {
424 s->lit = (literal_t *) safe_malloc(nvar * sizeof(literal_t));
425 s->level_index = (uint32_t *) safe_malloc(DEFAULT_NLEVELS * sizeof(uint32_t));
426 s->level_index[0] = 0;
427 s->top = 0;
428 s->prop_ptr = 0;
429 s->theory_ptr = 0;
430 s->nlevels = DEFAULT_NLEVELS;
431 }
432
433 /*
434 * Extend the size: nvar = new size
435 */
extend_stack(prop_stack_t * s,uint32_t nvar)436 static void extend_stack(prop_stack_t *s, uint32_t nvar) {
437 s->lit = (literal_t *) safe_realloc(s->lit, nvar * sizeof(literal_t));
438 }
439
440 /*
441 * Extend the level_index array by 50%
442 */
increase_stack_levels(prop_stack_t * s)443 static void increase_stack_levels(prop_stack_t *s) {
444 uint32_t n;
445
446 n = s->nlevels;
447 n += n>>1;
448 s->level_index = (uint32_t *) safe_realloc(s->level_index, n * sizeof(uint32_t));
449 s->nlevels = n;
450 }
451
452 /*
453 * Reset the stack (empty it)
454 */
reset_stack(prop_stack_t * s)455 static void reset_stack(prop_stack_t *s) {
456 s->top = 0;
457 s->prop_ptr = 0;
458 s->theory_ptr = 0;
459 s->level_index[0] = 0;
460 }
461
462
463 /*
464 * Free memory used by stack s
465 */
delete_stack(prop_stack_t * s)466 static void delete_stack(prop_stack_t *s) {
467 free(s->lit);
468 free(s->level_index);
469 }
470
471 /*
472 * Push literal l on top of stack s
473 */
push_literal(prop_stack_t * s,literal_t l)474 static void push_literal(prop_stack_t *s, literal_t l) {
475 uint32_t i;
476 i = s->top;
477 s->lit[i] = l;
478 s->top = i + 1;
479 }
480
481
482
483
484 /**********
485 * HEAP *
486 *********/
487
488 /*
489 * Initialize heap for n variables
490 * - heap is initially empty: heap_last = 0
491 * - heap[0] = -1 is a marker, with activity[-1] higher
492 * than any variable activity.
493 * - we also use -2 as a marker with negative activity
494 * - activity increment and threshold are set to their
495 * default initial value.
496 */
init_heap(var_heap_t * heap,uint32_t n)497 static void init_heap(var_heap_t *heap, uint32_t n) {
498 uint32_t i;
499 double *tmp;
500
501 heap->size = n;
502 tmp = (double *) safe_malloc((n+2) * sizeof(double));
503 heap->activity = tmp + 2;
504 heap->heap_index = (int32_t *) safe_malloc(n * sizeof(int32_t));
505 heap->heap = (bvar_t *) safe_malloc((n+1) * sizeof(bvar_t));
506
507 for (i=0; i<n; i++) {
508 heap->heap_index[i] = -1;
509 heap->activity[i] = 0.0;
510 }
511
512 heap->activity[-2] = -1.0;
513 heap->activity[-1] = DBL_MAX;
514 heap->heap[0] = -1;
515 heap->heap_last = 0;
516
517 heap->act_increment = INIT_VAR_ACTIVITY_INCREMENT;
518 heap->inv_act_decay = 1/VAR_DECAY_FACTOR;
519 }
520
521 /*
522 * Extend the heap for n variables
523 */
extend_heap(var_heap_t * heap,uint32_t n)524 static void extend_heap(var_heap_t *heap, uint32_t n) {
525 uint32_t old_size, i;
526 double *tmp;
527
528 old_size = heap->size;
529 assert(old_size < n);
530 heap->size = n;
531 tmp = heap->activity - 2;
532 tmp = (double *) safe_realloc(tmp, (n+2) * sizeof(double));
533 heap->activity = tmp + 2;
534 heap->heap_index = (int32_t *) safe_realloc(heap->heap_index, n * sizeof(int32_t));
535 heap->heap = (int32_t *) safe_realloc(heap->heap, (n+1) * sizeof(int32_t));
536
537 for (i=old_size; i<n; i++) {
538 heap->heap_index[i] = -1;
539 heap->activity[i] = 0.0;
540 }
541 }
542
543 /*
544 * Free the heap
545 */
delete_heap(var_heap_t * heap)546 static void delete_heap(var_heap_t *heap) {
547 safe_free(heap->activity - 2);
548 safe_free(heap->heap_index);
549 safe_free(heap->heap);
550 }
551
552
553 /*
554 * Reset: remove all variables from the heap and set their activities to 0
555 */
reset_heap(var_heap_t * heap)556 static void reset_heap(var_heap_t *heap) {
557 uint32_t i, n;
558
559 n = heap->size;
560 for (i=0; i<n; i++) {
561 heap->heap_index[i] = -1;
562 heap->activity[i] = 0.0;
563 }
564 heap->heap_last = 0;
565
566 // reset activity parameters: this makes a difference (2010/08/10)
567 heap->act_increment = INIT_VAR_ACTIVITY_INCREMENT;
568 heap->inv_act_decay = 1/VAR_DECAY_FACTOR;
569 }
570
571
572 /*
573 * EXPERIMENT: TEST TWO HEAP ORDERINGS
574 * - if BREAK_TIES is set, then ties are broken by ranking
575 * the variable with smallest index higher than the other.
576 * (seems to work better on bitvector benchmarks)
577 * - otherwise, we don't attempt to break ties.
578 *
579 * NOTE: if BREAK_TIES is set, then rescale_var_activities
580 * may not preserve the intended heap ordering. We ignore this
581 * issue for now, it should not matter much anyway??
582 */
583
584 #define BREAK_TIES 1
585
586 /*
587 * Comparison: return true if x precedes y in the heap ordering (strict ordering)
588 * - ax = activity of x
589 * - ay = activity of y
590 */
heap_cmp(bvar_t x,bvar_t y,double ax,double ay)591 static inline bool heap_cmp(bvar_t x, bvar_t y, double ax, double ay) {
592 #if BREAK_TIES
593 return (ax > ay) || (ax == ay && x < y);
594 #else
595 return ax > ay;
596 #endif
597 }
598
599 // variant: act = activity array
heap_precedes(double * act,bvar_t x,bvar_t y)600 static inline bool heap_precedes(double *act, bvar_t x, bvar_t y) {
601 return heap_cmp(x, y, act[x], act[y]);
602 }
603
604
605
606 /*
607 * Move x up in the heap.
608 * i = current position of x in the heap (or heap_last if x is being inserted)
609 */
update_up(var_heap_t * heap,bvar_t x,uint32_t i)610 static void update_up(var_heap_t *heap, bvar_t x, uint32_t i) {
611 double ax, *act;
612 int32_t *index;
613 bvar_t *h, y;
614 uint32_t j;
615
616 h = heap->heap;
617 index = heap->heap_index;
618 act = heap->activity;
619
620 ax = act[x];
621
622 j = i >> 1; // parent of i
623 y = h[j]; // variable at position j in the heap
624
625 // The loop terminates since act[h[0]] = DBL_MAX and h[0] = -1
626 while (heap_cmp(x, y, ax, act[y])) {
627 // move y down, into position i
628 h[i] = y;
629 index[y] = i;
630
631 // move i and j up
632 i = j;
633 j >>= 1;
634 y = h[j];
635 }
636
637 // i is the new position for variable x
638 h[i] = x;
639 index[x] = i;
640 }
641
642
643 /*
644 * Remove element at index i in the heap.
645 * Replace it by the current last element.
646 */
update_down(var_heap_t * heap,uint32_t i)647 static void update_down(var_heap_t *heap, uint32_t i) {
648 double *act;
649 int32_t *index;
650 bvar_t *h;
651 double ax, ay, az;
652 bvar_t x, y, z;
653 uint32_t j, last;
654
655 last = heap->heap_last;
656 heap->heap_last = last - 1;
657 if (last == i) return; // last element was removed
658
659 h = heap->heap;
660 index = heap->heap_index;
661 act = heap->activity;
662
663 assert(i < last && act[h[i]] >= act[h[last]]);
664
665 z = h[last]; // last element
666 az = act[z]; // activity of last heap element.
667
668 // set end marker: act[-2] is less than any variable activity
669 h[last] = -2;
670
671 j = 2 * i; // left child of i
672
673 while (j < last) {
674 /*
675 * find child of i with highest activity.
676 * Since we've set h[last] = -2, we don't need to check for j+1 < last
677 */
678 x = h[j];
679 ax = act[x];
680 y = h[j+1];
681 ay = act[y];
682 if (heap_cmp(y, x, ay, ax)) {
683 j ++;
684 x = y;
685 ax = ay;
686 }
687
688 // x = child of node i of highest activity
689 // j = position of x in the heap (j = 2i or j = 2i+1)
690 if (heap_cmp(z, x, az, ax)) break;
691
692 // move x up, into heap[i]
693 h[i] = x;
694 index[x] = i;
695
696 // go down one step.
697 i = j;
698 j <<= 1;
699 }
700
701 h[i] = z;
702 index[z] = i;
703 }
704
705
706 /*
707 * Insert x into the heap, using its current activity.
708 * No effect if x is already in the heap.
709 * - x must be between 0 and nvars - 1
710 */
heap_insert(var_heap_t * heap,bvar_t x)711 static void heap_insert(var_heap_t *heap, bvar_t x) {
712 if (heap->heap_index[x] < 0) {
713 // x not in the heap
714 heap->heap_last ++;
715 update_up(heap, x, heap->heap_last);
716 }
717 }
718
719 /*
720 * Remove x from the heap
721 */
heap_remove(var_heap_t * heap,bvar_t x)722 static void heap_remove(var_heap_t *heap, bvar_t x) {
723 int32_t i, j;
724 bvar_t y;
725
726 i = heap->heap_index[x];
727 if (i < 0) return; // x is not in the heap
728
729 heap->heap_index[x] = -1;
730
731 j = heap->heap_last;
732 y = heap->heap[j]; // last variable
733
734 if (i == j) {
735 // x was the last element
736 assert(x == y);
737 heap->heap_last --;
738 } else if (heap_precedes(heap->activity, x, y)) {
739 // in update down, h[i] is replaced by last element (i.e. y)
740 update_down(heap, i);
741 } else {
742 // replace x by y and move y up the heap
743 heap->heap[i] = y;
744 heap->heap_last --;
745 update_up(heap, y, i);
746 }
747 }
748
749
750 /*
751 * Check whether the heap is empty
752 */
heap_is_empty(var_heap_t * heap)753 static inline bool heap_is_empty(var_heap_t *heap) {
754 return heap->heap_last == 0;
755 }
756
757
758 /*
759 * Get and remove the top element
760 * - the heap must not be empty
761 */
heap_get_top(var_heap_t * heap)762 static bvar_t heap_get_top(var_heap_t *heap) {
763 bvar_t top;
764
765 assert(heap->heap_last > 0);
766
767 // remove top element
768 top = heap->heap[1];
769 heap->heap_index[top] = -1;
770
771 // repair the heap
772 update_down(heap, 1);
773
774 return top;
775 }
776
777
778 /*
779 * Rescale variable activities: divide by VAR_ACTIVITY_THRESHOLD
780 * \param heap = pointer to a heap structure
781 * \param n = number of variables
782 */
rescale_var_activities(var_heap_t * heap,uint32_t n)783 static void rescale_var_activities(var_heap_t *heap, uint32_t n) {
784 uint32_t i;
785 double *act;
786
787 heap->act_increment *= INV_VAR_ACTIVITY_THRESHOLD;
788 act = heap->activity;
789 for (i=0; i<n; i++) {
790 act[i] *= INV_VAR_ACTIVITY_THRESHOLD;
791 }
792 }
793
794
795
796 /*****************
797 * TRAIL STACK *
798 ****************/
799
800 /*
801 * Initialize a trail stack. Size = 0
802 */
init_trail_stack(trail_stack_t * stack)803 static void init_trail_stack(trail_stack_t *stack) {
804 stack->size = 0;
805 stack->top = 0;
806 stack->data = NULL;
807 }
808
809 /*
810 * Save level:
811 * - v = number of variables
812 * - u = number of unit clauses
813 * - b = number of binary clauses
814 * - p = number of (non-unit and non-binary) problem clauses
815 * - b_ptr = boolean propagation pointer
816 * - t_ptr = theory propagation pointer
817 */
trail_stack_save(trail_stack_t * stack,uint32_t v,uint32_t u,uint32_t b,uint32_t p,uint32_t b_ptr,uint32_t t_ptr)818 static void trail_stack_save(trail_stack_t *stack, uint32_t v, uint32_t u, uint32_t b, uint32_t p,
819 uint32_t b_ptr, uint32_t t_ptr) {
820 uint32_t i, n;
821
822 i = stack->top;
823 n = stack->size;
824 if (i == n) {
825 if (n == 0) {
826 n = DEFAULT_DPLL_TRAIL_SIZE;
827 } else {
828 n += n;
829 if (n >= MAX_DPLL_TRAIL_SIZE) {
830 out_of_memory();
831 }
832 }
833 stack->data = (trail_t *) safe_realloc(stack->data, n * sizeof(trail_t));
834 stack->size = n;
835 }
836 stack->data[i].nvars = v;
837 stack->data[i].nunits = u;
838 stack->data[i].nbins = b;
839 stack->data[i].nclauses = p;
840 stack->data[i].prop_ptr = b_ptr;
841 stack->data[i].theory_ptr = t_ptr;
842
843 stack->top = i + 1;
844 }
845
846
847 /*
848 * Get top record
849 */
trail_stack_top(trail_stack_t * stack)850 static inline trail_t *trail_stack_top(trail_stack_t *stack) {
851 assert(stack->top > 0);
852 return stack->data + (stack->top - 1);
853 }
854
855 /*
856 * Remove top record
857 */
trail_stack_pop(trail_stack_t * stack)858 static inline void trail_stack_pop(trail_stack_t *stack) {
859 assert(stack->top > 0);
860 stack->top --;
861 }
862
863
864 /*
865 * Empty the stack
866 */
reset_trail_stack(trail_stack_t * stack)867 static inline void reset_trail_stack(trail_stack_t *stack) {
868 stack->top = 0;
869 }
870
871
872 /*
873 * Delete
874 */
delete_trail_stack(trail_stack_t * stack)875 static inline void delete_trail_stack(trail_stack_t *stack) {
876 safe_free(stack->data);
877 stack->data = NULL;
878 }
879
880
881
882 /******************
883 * ATOM TABLE *
884 *****************/
885
886 /*
887 * Initialization: the table is initially empty.
888 */
init_atom_table(atom_table_t * tbl)889 static void init_atom_table(atom_table_t *tbl) {
890 tbl->has_atom = NULL;
891 tbl->atom = NULL;
892 tbl->size = 0;
893 tbl->natoms = 0;
894 }
895
896
897 /*
898 * Make room for more atoms: n = new size
899 */
resize_atom_table(atom_table_t * tbl,uint32_t n)900 static void resize_atom_table(atom_table_t *tbl, uint32_t n) {
901 uint32_t k;
902
903 // round up to a multiple of 8
904 n = (n + 7) & ~7;
905 k = tbl->size;
906
907 if (n > k) {
908 assert(n <= MAX_ATOM_TABLE_SIZE);
909
910 tbl->has_atom = extend_bitvector(tbl->has_atom, n);
911 tbl->atom = (void **) safe_realloc(tbl->atom, n * sizeof(void *));
912 tbl->size = n;
913
914 // clear new bitvector elements
915 clear_bitvector(tbl->has_atom + (k>>3), n - k);
916 }
917 }
918
919
920 /*
921 * Deletion
922 */
delete_atom_table(atom_table_t * tbl)923 static void delete_atom_table(atom_table_t *tbl) {
924 delete_bitvector(tbl->has_atom);
925 safe_free(tbl->atom);
926 tbl->has_atom = NULL;
927 tbl->atom = NULL;
928 }
929
930
931 /*
932 * Reset the table: empty it
933 */
reset_atom_table(atom_table_t * tbl)934 static void reset_atom_table(atom_table_t *tbl) {
935 tbl->natoms = 0;
936 clear_bitvector(tbl->has_atom, tbl->size);
937 }
938
939
940
941
942 /*
943 * Attach atom atm to variable v:
944 * - v must not have an atom attached already and there must be enough
945 * room in tbl for variable v (i.e., tbl must be resized before this
946 * function is called).
947 */
add_atom(atom_table_t * tbl,bvar_t v,void * atm)948 static void add_atom(atom_table_t *tbl, bvar_t v, void *atm) {
949 assert(v < tbl->size && !tst_bit(tbl->has_atom, v));
950 set_bit(tbl->has_atom, v);
951 tbl->atom[v] = atm;
952 tbl->natoms ++;
953 }
954
955
956 /*
957 * Remove the atom attached to v
958 */
remove_atom(atom_table_t * tbl,bvar_t v)959 static void remove_atom(atom_table_t *tbl, bvar_t v) {
960 assert(v < tbl->size && tst_bit(tbl->has_atom, v));
961 clr_bit(tbl->has_atom, v);
962 tbl->atom[v] = NULL;
963 tbl->natoms --;
964 }
965
966
967
968
969 /*****************
970 * LEMMA QUEUE *
971 ****************/
972
973 /*
974 * Initialize queue: nothing is allocated yet
975 */
init_lemma_queue(lemma_queue_t * queue)976 static void init_lemma_queue(lemma_queue_t *queue) {
977 queue->capacity = 0;
978 queue->nblocks = 0;
979 queue->free_block = 0;
980 queue->block = NULL;
981 }
982
983 /*
984 * Delete all allocated blocks and the array queue->block
985 */
delete_lemma_queue(lemma_queue_t * queue)986 static void delete_lemma_queue(lemma_queue_t *queue) {
987 uint32_t i;
988
989 for (i=0; i<queue->nblocks; i++) {
990 safe_free(queue->block[i]);
991 }
992 safe_free(queue->block);
993 queue->block = NULL;
994 }
995
996
997 /*
998 * Increase capacity: increase the size of the block array
999 */
increase_lemma_queue_capacity(lemma_queue_t * queue)1000 static void increase_lemma_queue_capacity(lemma_queue_t *queue) {
1001 uint32_t n;
1002
1003 n = 2 * queue->capacity; // new capacity
1004 if (n == 0) {
1005 n = DEF_LEMMA_BLOCKS;
1006 }
1007
1008 if (n >= MAX_LEMMA_BLOCKS) {
1009 out_of_memory();
1010 }
1011
1012 queue->block = (lemma_block_t **) safe_realloc(queue->block, n * sizeof(lemma_block_t *));
1013 queue->capacity = n;
1014 }
1015
1016
1017 /*
1018 * Allocate a block of the given size
1019 */
new_lemma_block(uint32_t size)1020 static lemma_block_t *new_lemma_block(uint32_t size) {
1021 lemma_block_t *tmp;
1022
1023 if (size >= MAX_LEMMA_BLOCK_SIZE) {
1024 out_of_memory();
1025 }
1026
1027 tmp = (lemma_block_t *) safe_malloc(sizeof(lemma_block_t) + size * sizeof(literal_t));
1028 tmp->size = size;
1029 tmp->ptr = 0;
1030
1031 return tmp;
1032 }
1033
1034
1035 /*
1036 * Find a block b that has space for n literals (i.e., b->size - b->ptr >= n)
1037 * - use the top_block if that works, otherwise use the next block
1038 * - allocate blocks if necessary
1039 */
find_block_for_lemma(lemma_queue_t * queue,uint32_t n)1040 static lemma_block_t *find_block_for_lemma(lemma_queue_t *queue, uint32_t n) {
1041 uint32_t i, j;
1042 lemma_block_t *tmp;
1043
1044 /*
1045 * invariants:
1046 * 0 <= free_block <= nblocks <= capacity
1047 * block has size = capacity
1048 * if 0 <= i < free_block-1 then block[i] is full
1049 * if free_block > 0, then block[free_block-1] is not empty and not full
1050 * if free_block <= i < nblocks then block[i] is allocated and empty
1051 * if nblocks <= i < capacity then block[i] is not allocated
1052 */
1053 i = queue->free_block;
1054 if (i > 0) {
1055 // try the current block
1056 tmp = queue->block[i-1];
1057 assert(tmp != NULL && tmp->ptr > 0);
1058 if (tmp->size - tmp->ptr >= n) return tmp;
1059 }
1060
1061 // current block does not exist or it's full.
1062 // search for a large enough block among block[free_blocks ... nblocks-1]
1063 for (j=i; j<queue->nblocks; j++) {
1064 tmp = queue->block[j];
1065 assert(tmp != NULL && tmp->ptr == 0);
1066 if (tmp->size >= n) {
1067 // swap block[i] and block[j]
1068 queue->block[j] = queue->block[i];
1069 queue->block[i] = tmp;
1070 queue->free_block ++;
1071 return tmp;
1072 }
1073 }
1074
1075 // we need to allocate a new block, large enough for n literals
1076 if (n < DEF_LEMMA_BLOCK_SIZE) {
1077 n = DEF_LEMMA_BLOCK_SIZE;
1078 }
1079 tmp = new_lemma_block(n);
1080
1081 // make room in queue->block if necessary
1082 j = queue->nblocks;
1083 if (j >= queue->capacity) {
1084 increase_lemma_queue_capacity(queue);
1085 assert(queue->nblocks < queue->capacity);
1086 }
1087
1088 queue->block[j] = queue->block[i];
1089 queue->block[i] = tmp;
1090 queue->free_block ++;
1091 queue->nblocks ++;
1092
1093 return tmp;
1094 }
1095
1096
1097 /*
1098 * Push literal array a[0] ... a[n-1] as a lemma
1099 */
push_lemma(lemma_queue_t * queue,uint32_t n,literal_t * a)1100 static void push_lemma(lemma_queue_t *queue, uint32_t n, literal_t *a) {
1101 lemma_block_t *blk;
1102 uint32_t i;
1103 literal_t *b;
1104
1105 blk = find_block_for_lemma(queue, n+1);
1106 assert(queue->free_block > 0 && blk == queue->block[queue->free_block-1]
1107 && blk->ptr + n < blk->size);
1108
1109 b = blk->data + blk->ptr;
1110 for (i=0; i<n; i++) {
1111 b[i] = a[i];
1112 }
1113 b[i] = null_literal; // end-marker;
1114 i++;
1115 blk->ptr += i;
1116 }
1117
1118
1119
1120
1121
1122 /*
1123 * Empty the queue
1124 */
reset_lemma_queue(lemma_queue_t * queue)1125 static void reset_lemma_queue(lemma_queue_t *queue) {
1126 uint32_t i;
1127
1128 if (queue->nblocks > LEMMA_BLOCKS_TO_KEEP) {
1129 // keep 4 blocks, delete the others to save memory
1130 for (i=0; i<LEMMA_BLOCKS_TO_KEEP; i++) {
1131 queue->block[i]->ptr = 0;
1132 }
1133 while (i < queue->nblocks) {
1134 safe_free(queue->block[i]);
1135 queue->block[i] = NULL;
1136 i ++;
1137 }
1138 queue->nblocks = LEMMA_BLOCKS_TO_KEEP;
1139
1140 } else {
1141 // keep all the allocated blocks
1142 for (i=0; i<queue->nblocks; i++) {
1143 queue->block[i]->ptr = 0;
1144 }
1145 }
1146 queue->free_block = 0;
1147 }
1148
1149
1150 /*
1151 * Check whether the queue is empty
1152 */
empty_lemma_queue(lemma_queue_t * queue)1153 static inline bool empty_lemma_queue(lemma_queue_t *queue) {
1154 return queue->free_block == 0;
1155 }
1156
1157
1158
1159
1160
1161 /************************
1162 * CHECKPOINT STACK *
1163 ***********************/
1164
1165 /*
1166 * Initialization: nothing is allocated
1167 */
init_checkpoint_stack(checkpoint_stack_t * stack)1168 static void init_checkpoint_stack(checkpoint_stack_t *stack) {
1169 stack->size = 0;
1170 stack->top = 0;
1171 stack->data = NULL;
1172 }
1173
1174 /*
1175 * Delete
1176 */
delete_checkpoint_stack(checkpoint_stack_t * stack)1177 static void delete_checkpoint_stack(checkpoint_stack_t *stack) {
1178 safe_free(stack->data);
1179 stack->data = NULL;
1180 }
1181
1182
1183 /*
1184 * Increase the size
1185 */
extend_checkpoint_stack(checkpoint_stack_t * stack)1186 static void extend_checkpoint_stack(checkpoint_stack_t *stack) {
1187 uint32_t n;
1188
1189 n = stack->size;
1190 n += n>>1; // make it 50% larger
1191 if (n == 0) {
1192 // first allocation
1193 n = DEF_CHECKPOINT_STACK_SIZE;
1194 }
1195
1196 if (n >= MAX_CHECKPOINT_STACK_SIZE) {
1197 out_of_memory();
1198 }
1199
1200 stack->data = (checkpoint_t *) safe_realloc(stack->data, n * sizeof(checkpoint_t));
1201 stack->size = n;
1202 }
1203
1204
1205 /*
1206 * Check whether the stack is empty
1207 */
empty_checkpoint_stack(checkpoint_stack_t * stack)1208 static inline bool empty_checkpoint_stack(checkpoint_stack_t *stack) {
1209 return stack->top == 0;
1210 }
1211
non_empty_checkpoint_stack(checkpoint_stack_t * stack)1212 static inline bool non_empty_checkpoint_stack(checkpoint_stack_t *stack) {
1213 return stack->top > 0;
1214 }
1215
1216
1217 /*
1218 * Get the top checkpoint
1219 */
top_checkpoint(checkpoint_stack_t * stack)1220 static inline checkpoint_t *top_checkpoint(checkpoint_stack_t *stack) {
1221 assert(non_empty_checkpoint_stack(stack));
1222 return stack->data + (stack->top - 1);
1223 }
1224
1225 /*
1226 * Remove the top checkpoint
1227 */
pop_checkpoint(checkpoint_stack_t * stack)1228 static inline void pop_checkpoint(checkpoint_stack_t *stack) {
1229 assert(non_empty_checkpoint_stack(stack));
1230 stack->top --;
1231 }
1232
1233 /*
1234 * Push a checkpoint
1235 * - d = decision level,
1236 * - n = number of terms
1237 */
push_checkpoint(checkpoint_stack_t * stack,uint32_t d,uint32_t n)1238 static void push_checkpoint(checkpoint_stack_t *stack, uint32_t d, uint32_t n) {
1239 uint32_t i;
1240
1241 i = stack->top;
1242 if (i >= stack->size) {
1243 extend_checkpoint_stack(stack);
1244 assert(i < stack->size);
1245 }
1246 stack->data[i].dlevel = d;
1247 stack->data[i].nvars = n;
1248 stack->top = i+1;
1249 }
1250
1251
1252 /*
1253 * Reset: empty the stack
1254 */
reset_checkpoint_stack(checkpoint_stack_t * stack)1255 static inline void reset_checkpoint_stack(checkpoint_stack_t *stack) {
1256 stack->top = 0;
1257 }
1258
1259
1260
1261
1262
1263
1264 /************************
1265 * STATISTICS RECORD *
1266 ***********************/
1267
1268
1269 /*
1270 * Initialize a statistics record
1271 */
init_statistics(dpll_stats_t * stat)1272 static void init_statistics(dpll_stats_t *stat) {
1273 stat->restarts = 0;
1274 stat->simplify_calls = 0;
1275 stat->reduce_calls = 0;
1276 stat->remove_calls = 0;
1277 stat->decisions = 0;
1278 stat->random_decisions = 0;
1279 stat->propagations = 0;
1280 stat->conflicts = 0;
1281 stat->th_props = 0;
1282 stat->th_prop_lemmas = 0;
1283 stat->th_conflicts = 0;
1284 stat->th_conflict_lemmas = 0;
1285 stat->prob_literals = 0;
1286 stat->learned_literals = 0;
1287 stat->prob_clauses_deleted = 0;
1288 stat->learned_clauses_deleted = 0;
1289 stat->bin_clauses_deleted = 0;
1290 stat->literals_before_simpl = 0;
1291 stat->subsumed_literals = 0;
1292 }
1293
1294
1295 /*
1296 * Reset = same thing as init
1297 */
reset_statistics(dpll_stats_t * stats)1298 static inline void reset_statistics(dpll_stats_t *stats) {
1299 init_statistics(stats);
1300 }
1301
1302
1303
1304 /**********************************
1305 * EXPERIMENTAL: EQUALITY TABLE *
1306 *********************************/
1307
1308 #if 0
1309
1310 /*
1311 * Allocate and initialize the etable
1312 */
1313 void smt_core_make_etable(smt_core_t *s) {
1314 booleq_table_t *tmp;
1315
1316 assert(s->etable == NULL);
1317 tmp = (booleq_table_t *) safe_malloc(sizeof(booleq_table_t));
1318 init_booleq_table(tmp);
1319 s->etable = tmp;
1320 }
1321
1322
1323 /*
1324 * Record l = (xor a b)
1325 */
1326 void smt_core_record_xor_def(smt_core_t *s, literal_t l, literal_t a, literal_t b) {
1327 assert(s->etable != NULL);
1328 booleq_table_record_xor(s->etable, l, a, b);
1329
1330 print_literal(stdout, l);
1331 printf(" := (xor ");
1332 print_literal(stdout, a);
1333 printf(" ");
1334 print_literal(stdout, b);
1335 printf(")\n");
1336 }
1337
1338
1339 /*
1340 * Delete the table if any
1341 */
1342 static void delete_etable(smt_core_t *s) {
1343 if (s->etable != NULL) {
1344 delete_booleq_table(s->etable);
1345 safe_free(s->etable);
1346 s->etable = NULL;
1347 }
1348 }
1349
1350
1351 /*
1352 * Reset it
1353 */
1354 static void reset_etable(smt_core_t *s) {
1355 if (s->etable != NULL) {
1356 reset_booleq_table(s->etable);
1357 }
1358 }
1359
1360
1361 /*
1362 * Display details about a learned clause if it contains
1363 * at least two xor or equality atoms
1364 */
1365 static void test_eq_clause(smt_core_t *s, const char *msg, uint32_t n, literal_t *a) {
1366 uint32_t i, neq;
1367 literal_t u, v;
1368
1369 assert(s->etable != NULL);
1370
1371 neq = 0;
1372 for (i=0; i<n; i++) {
1373 if (literal_is_eq(s->etable, a[i])) {
1374 neq ++;
1375 }
1376 }
1377
1378 if (neq >= 0) {
1379 printf("\n--- Learned clause %"PRIu64" %s ---\n", s->stats.conflicts, msg);
1380 printf("{");
1381 for (i=0; i<n; i++) {
1382 printf(" ");
1383 print_literal(stdout, a[i]);
1384 }
1385 printf(" }\n");
1386
1387 for (i=0; i<n; i++) {
1388 if (get_booleq(s->etable, not(a[i]), &u, &v)) {
1389 print_literal(stdout, not(a[i]));
1390 printf(" := (eq ");
1391 print_literal(stdout, u);
1392 printf(" ");
1393 print_literal(stdout, v);
1394 printf(")\n");
1395 }
1396 }
1397 printf("\n");
1398 }
1399 }
1400
1401
1402 /*
1403 * Same thing for the conflict clause
1404 */
1405 static void test_eq_conflict(smt_core_t *s) {
1406 literal_t *c;
1407 literal_t u, v;
1408
1409 assert(s->etable != NULL);
1410
1411 if (! s->theory_conflict) {
1412 c = s->conflict;
1413 printf("\n--- Conflict %"PRIu64" ---\n", s->stats.conflicts);
1414 printf("{");
1415 while (*c >= 0) {
1416 printf(" ");
1417 print_literal(stdout, *c);
1418 c ++;
1419 }
1420 printf(" }\n");
1421
1422 c = s->conflict;
1423 while (*c >= 0) {
1424 if (get_booleq(s->etable, not(*c), &u, &v)) {
1425 print_literal(stdout, not(*c));
1426 printf(" := (eq ");
1427 print_literal(stdout, u);
1428 printf(" ");
1429 print_literal(stdout, v);
1430 printf(")\n");
1431 }
1432 c ++;
1433 }
1434 }
1435 }
1436
1437 #endif
1438
1439
1440 /************************
1441 * GENERAL OPERATIONS *
1442 ***********************/
1443
1444 /*
1445 * Initialize an smt core
1446 * - n = initial vsize = size of the variable-indexed arrays
1447 * - th = theory solver
1448 * - ctrl = descriptor of control functions for th
1449 * - smt = descriptor of the SMT functions for th
1450 * - mode = to select optional features
1451 * This creates the predefined "constant" variable and the true/false literals
1452 *
1453 * The clause and variable activity increments, and the randomness
1454 * parameters are set to their default values
1455 */
init_smt_core(smt_core_t * s,uint32_t n,void * th,th_ctrl_interface_t * ctrl,th_smt_interface_t * smt,smt_mode_t mode)1456 void init_smt_core(smt_core_t *s, uint32_t n, void *th,
1457 th_ctrl_interface_t *ctrl, th_smt_interface_t *smt,
1458 smt_mode_t mode) {
1459 uint32_t lsize;
1460
1461 s->th_solver = th;
1462 s->th_ctrl = *ctrl; // make a full copy
1463 s->th_smt = *smt; // ditto
1464 s->bool_only = false;
1465
1466 s->status = STATUS_IDLE;
1467
1468 switch (mode) {
1469 case SMT_MODE_BASIC:
1470 s->option_flag = 0;
1471 break;
1472
1473 case SMT_MODE_PUSHPOP:
1474 s->option_flag = PUSH_POP_MASK;
1475 break;
1476
1477 default:
1478 s->option_flag = PUSH_POP_MASK|CLEAN_INTERRUPT_MASK;
1479 break;
1480 }
1481
1482 // ensure there's room for the constants
1483 if (n == 0) n = 1;
1484 lsize = 2 * n;
1485
1486 if (n >= MAX_VARIABLES) {
1487 out_of_memory();
1488 }
1489
1490 // counters
1491 s->nvars = 1;
1492 s->nlits = 2;
1493 s->vsize = n;
1494 s->lsize = lsize;
1495
1496 s->nb_clauses = 0;
1497 s->nb_prob_clauses = 0;
1498 s->nb_bin_clauses = 0;
1499 s->nb_unit_clauses = 0;
1500
1501 s->simplify_bottom = 0;
1502 s->simplify_props = 0;
1503 s->simplify_threshold = 0;
1504
1505 s->aux_literals = 0;
1506 s->aux_clauses = 0;
1507
1508 s->decision_level = 0;
1509 s->base_level = 0;
1510
1511 // heuristic parameters
1512 s->cla_inc = INIT_CLAUSE_ACTIVITY_INCREMENT;
1513 s->inv_cla_decay = 1/CLAUSE_DECAY_FACTOR;
1514 s->prng = CORE_PRNG_SEED;
1515 s->scaled_random = (uint32_t) (VAR_RANDOM_FACTOR * VAR_RANDOM_SCALE);
1516
1517 // theory caching: disabled initially
1518 s->th_cache_enabled = false;
1519 s->th_cache_cl_size = 0;
1520
1521 // conflict data: no need to initialize conflict_buffer
1522 s->inconsistent = false;
1523 s->theory_conflict = false;
1524 s->conflict = NULL;
1525 s->false_clause = NULL;
1526
1527 // auxiliary buffers
1528 init_ivector(&s->buffer, DEF_LBUFFER_SIZE);
1529 init_ivector(&s->buffer2, DEF_LBUFFER_SIZE);
1530 init_ivector(&s->explanation, DEF_LBUFFER_SIZE);
1531
1532 // assumptions
1533 s->has_assumptions = false;
1534 s->num_assumptions = 0;
1535 s->assumption_index = 0;
1536 s->assumptions = NULL;
1537 s->bad_assumption = null_literal;
1538
1539 // clause database: all empty
1540 s->problem_clauses = new_clause_vector(DEF_CLAUSE_VECTOR_SIZE);
1541 s->learned_clauses = new_clause_vector(DEF_CLAUSE_VECTOR_SIZE);
1542 init_ivector(&s->binary_clauses, 0);
1543
1544
1545 /*
1546 * Variable-indexed arrays
1547 *
1548 * level and value are indexed from -1 to n-1
1549 * level[-1] = UINT32_MAX (never assigned, marker variable)
1550 * value[-1] = VAL_UNDEF_FALSE (not assigned)
1551 */
1552 s->value = (uint8_t *) safe_malloc((n + 1) * sizeof(uint8_t)) + 1;
1553 s->antecedent = (antecedent_t *) safe_malloc(n * sizeof(antecedent_t));
1554 s->level = (uint32_t *) safe_malloc((n + 1) * sizeof(uint32_t)) + 1;
1555 s->mark = allocate_bitvector(n);
1556 s->level[-1] = UINT32_MAX;
1557 s->value[-1] = VAL_UNDEF_FALSE;
1558
1559 /*
1560 * Literal-indexed arrays
1561 */
1562 s->bin = (literal_t **) safe_malloc(lsize * sizeof(literal_t *));
1563 s->watch = (link_t *) safe_malloc(lsize * sizeof(link_t));
1564
1565 /*
1566 * Initialize data structures for true_literal and false_literal
1567 */
1568 assert(const_bvar == 0 && true_literal == 0 && false_literal == 1 && s->nvars > 0);
1569 s->level[const_bvar] = 0;
1570 s->value[const_bvar] = VAL_TRUE;
1571 set_bit(s->mark, const_bvar);
1572 assert(literal_value(s, true_literal) == VAL_TRUE &&
1573 literal_value(s, false_literal) == VAL_FALSE);
1574
1575 s->bin[true_literal] = NULL;
1576 s->bin[false_literal] = NULL;
1577 s->watch[true_literal] = NULL_LINK;
1578 s->watch[false_literal] = NULL_LINK;
1579
1580 init_stack(&s->stack, n);
1581 init_heap(&s->heap, n);
1582 init_lemma_queue(&s->lemmas);
1583 init_statistics(&s->stats);
1584 init_atom_table(&s->atoms);
1585 init_gate_table(&s->gates);
1586 init_trail_stack(&s->trail_stack);
1587 init_checkpoint_stack(&s->checkpoints);
1588 s->cp_flag = false;
1589
1590 s->etable = NULL;
1591 s->trace = NULL;
1592
1593 s->interrupt_push = false;
1594 }
1595
1596
1597
1598 /*
1599 * Replace the theory solver and interface descriptors
1600 * - this can used provided no atom/clause has been added yet
1601 */
smt_core_reset_thsolver(smt_core_t * s,void * th,th_ctrl_interface_t * ctrl,th_smt_interface_t * smt)1602 void smt_core_reset_thsolver(smt_core_t *s, void *th, th_ctrl_interface_t *ctrl,
1603 th_smt_interface_t *smt) {
1604 s->th_solver = th;
1605 s->th_ctrl = *ctrl; // make a full copy
1606 s->th_smt = *smt; // ditto
1607 }
1608
1609
1610 /*
1611 * Delete: free all allocated memory
1612 */
delete_smt_core(smt_core_t * s)1613 void delete_smt_core(smt_core_t *s) {
1614 uint32_t i, n;
1615 clause_t **cl;
1616
1617 delete_ivector(&s->buffer);
1618 delete_ivector(&s->buffer2);
1619 delete_ivector(&s->explanation);
1620
1621 // Delete all the clauses
1622 cl = s->problem_clauses;
1623 n = get_cv_size(cl);
1624 for (i=0; i<n; i++) {
1625 delete_clause(cl[i]);
1626 }
1627 delete_clause_vector(cl);
1628
1629 cl = s->learned_clauses;
1630 n = get_cv_size(cl);
1631 for (i=0; i<n; i++) {
1632 delete_learned_clause(cl[i]);
1633 }
1634 delete_clause_vector(cl);
1635
1636 delete_ivector(&s->binary_clauses);
1637
1638 // var-indexed arrays
1639 safe_free(s->value - 1);
1640 safe_free(s->antecedent);
1641 safe_free(s->level - 1);
1642 delete_bitvector(s->mark);
1643
1644 // literal-indexed arrays
1645 n = s->nlits;
1646 for (i=0; i<n; i++) {
1647 delete_literal_vector(s->bin[i]);
1648 }
1649 safe_free(s->bin);
1650 safe_free(s->watch);
1651
1652 delete_stack(&s->stack);
1653 delete_heap(&s->heap);
1654 delete_lemma_queue(&s->lemmas);
1655 delete_atom_table(&s->atoms);
1656 delete_gate_table(&s->gates);
1657 delete_trail_stack(&s->trail_stack);
1658 delete_checkpoint_stack(&s->checkpoints);
1659
1660 // EXPERIMENTAL
1661 // delete_etable(s);
1662 }
1663
1664
1665 /*
1666 * Reset: remove all variables, atoms, and clauses
1667 * - also calls reset on the attached theory solver
1668 * - we don't call atom_deleted for the solver.
1669 */
reset_smt_core(smt_core_t * s)1670 void reset_smt_core(smt_core_t *s) {
1671 uint32_t i, n;
1672 clause_t **cl;
1673
1674 s->status = STATUS_IDLE;
1675
1676 // reset buffers
1677 ivector_reset(&s->buffer);
1678 ivector_reset(&s->buffer2);
1679 ivector_reset(&s->explanation);
1680
1681 // assumptions
1682 s->has_assumptions = false;
1683 s->num_assumptions = 0;
1684 s->assumption_index = 0;
1685 s->assumptions = NULL;
1686 s->bad_assumption = null_literal;
1687
1688 // delete the clauses
1689 cl = s->problem_clauses;
1690 n = get_cv_size(cl);
1691 for (i=0; i<n; i++) {
1692 delete_clause(cl[i]);
1693 }
1694 reset_clause_vector(cl);
1695
1696 cl = s->learned_clauses;
1697 n = get_cv_size(cl);
1698 for (i=0; i<n; i++) {
1699 delete_learned_clause(cl[i]);
1700 }
1701 reset_clause_vector(cl);
1702
1703 ivector_reset(&s->binary_clauses);
1704
1705 // delete binary-watched literal vectors
1706 n = s->nlits;
1707 for (i=0; i<n; i++) {
1708 delete_literal_vector(s->bin[i]);
1709 }
1710
1711 reset_stack(&s->stack);
1712 reset_heap(&s->heap);
1713 reset_lemma_queue(&s->lemmas);
1714 reset_statistics(&s->stats);
1715 reset_atom_table(&s->atoms);
1716 reset_gate_table(&s->gates);
1717 reset_trail_stack(&s->trail_stack);
1718 reset_checkpoint_stack(&s->checkpoints);
1719 s->cp_flag = false;
1720
1721 // reset all counters
1722 s->nvars = 1;
1723 s->nlits = 2;
1724 s->nb_clauses = 0;
1725 s->nb_prob_clauses = 0; // fixed 2010/08/10 (was missing)
1726 s->nb_bin_clauses = 0;
1727 s->nb_unit_clauses = 0;
1728 s->simplify_bottom = 0;
1729 s->simplify_props = 0;
1730 s->simplify_threshold = 0;
1731 s->decision_level = 0;
1732 s->base_level = 0;
1733
1734 // heuristic parameters: it makes a difference to reset cla_inc
1735 s->cla_inc = INIT_CLAUSE_ACTIVITY_INCREMENT;
1736 s->inv_cla_decay = 1/CLAUSE_DECAY_FACTOR;
1737 s->prng = CORE_PRNG_SEED;
1738 s->scaled_random = (uint32_t) (VAR_RANDOM_FACTOR * VAR_RANDOM_SCALE);
1739
1740 // reset conflict data
1741 s->inconsistent = false;
1742 s->theory_conflict = false;
1743 s->conflict = NULL;
1744 s->false_clause = NULL;
1745
1746 // reset the theory solver
1747 s->th_ctrl.reset(s->th_solver);
1748
1749 // EXPERIMENTAL
1750 // reset_etable(s);
1751
1752 s->interrupt_push = false;
1753 }
1754
1755
1756
1757 /*
1758 * Extend solver: make room for more variables
1759 * - n = new vsize
1760 */
extend_smt_core(smt_core_t * s,uint32_t n)1761 static void extend_smt_core(smt_core_t *s, uint32_t n) {
1762 uint32_t lsize;
1763
1764 assert(n >= s->vsize);
1765
1766 if (n >= MAX_VARIABLES) {
1767 out_of_memory();
1768 }
1769
1770 lsize = 2 * n;
1771 s->vsize = n;
1772 s->lsize = lsize;
1773
1774 s->value = (uint8_t *) safe_realloc(s->value - 1, (n + 1) * sizeof(uint8_t)) + 1;
1775 s->antecedent = (antecedent_t *) safe_realloc(s->antecedent, n * sizeof(antecedent_t));
1776 s->level = (uint32_t *) safe_realloc(s->level - 1, (n + 1) * sizeof(uint32_t)) + 1;
1777 s->mark = extend_bitvector(s->mark, n);
1778
1779 s->bin = (literal_t **) safe_realloc(s->bin, lsize * sizeof(literal_t *));
1780 s->watch = (link_t *) safe_realloc(s->watch, lsize * sizeof(link_t));
1781
1782 extend_heap(&s->heap, n);
1783 extend_stack(&s->stack, n);
1784 }
1785
1786
1787
1788 /*
1789 * Change the heuristic parameters:
1790 * - must not be called when search is under way
1791 * - factor must be between 0 and 1.0
1792 */
set_var_decay_factor(smt_core_t * s,double factor)1793 void set_var_decay_factor(smt_core_t *s, double factor) {
1794 assert(s->status != STATUS_SEARCHING && 0.0 < factor && factor < 1.0);
1795 s->heap.inv_act_decay = 1/factor;
1796 }
1797
set_clause_decay_factor(smt_core_t * s,float factor)1798 void set_clause_decay_factor(smt_core_t *s, float factor) {
1799 assert(s->status != STATUS_SEARCHING && 0.0F < factor && factor < 1.0F);
1800 s->inv_cla_decay = 1/factor;
1801 }
1802
set_randomness(smt_core_t * s,float random_factor)1803 void set_randomness(smt_core_t *s, float random_factor) {
1804 assert(s->status != STATUS_SEARCHING && 0.0F <= random_factor && random_factor < 1.0F);
1805 s->scaled_random = (uint32_t)(random_factor * VAR_RANDOM_SCALE);
1806 }
1807
1808
1809 /*
1810 * Set the internal seed
1811 */
set_random_seed(smt_core_t * s,uint32_t x)1812 void set_random_seed(smt_core_t *s, uint32_t x) {
1813 s->prng = x;
1814 }
1815
1816
1817 /*
1818 * Set the trace file
1819 */
smt_core_set_trace(smt_core_t * s,tracer_t * tracer)1820 void smt_core_set_trace(smt_core_t *s, tracer_t *tracer) {
1821 assert(s->trace == NULL);
1822 s->trace = tracer;
1823 }
1824
1825
avg_learned_clause_size(smt_core_t * core)1826 extern double avg_learned_clause_size(smt_core_t *core) {
1827 uint32_t num_clauses;
1828 double r;
1829
1830 r = 0.0;
1831 num_clauses = num_learned_clauses(core);
1832 if (num_clauses > 0) {
1833 r = ((double) num_learned_literals(core)) /num_clauses;
1834 }
1835 return r;
1836 }
1837
1838
1839
1840 /**************************
1841 * VARIABLE ALLOCATION *
1842 *************************/
1843
1844 /*
1845 * Initialize all arrays for a new variable x
1846 * - antecedent[x] = NULL
1847 * - level[x] = UINT32_MAX
1848 * - mark[x] = 0
1849 * - value[x] = VAL_UNDEF_FALSE (negative polarity preferred)
1850 * - activity[x] = 0 (in heap)
1851 *
1852 * For l=pos_lit(x) and neg_lit(x):
1853 * - bin[l] = NULL
1854 * - watch[l] = NULL
1855 */
init_variable(smt_core_t * s,bvar_t x)1856 static void init_variable(smt_core_t *s, bvar_t x) {
1857 literal_t l0, l1;
1858
1859 clr_bit(s->mark, x);
1860 s->value[x] = VAL_UNDEF_FALSE;
1861 s->antecedent[x] = mk_literal_antecedent(null_literal);
1862 s->level[x] = UINT32_MAX;
1863
1864 // HACK for testing initial order
1865 // assert(s->heap.heap_index[x] < 0);
1866 // s->heap.activity[x] = (10000.0/(x+1));
1867 // end of HACK
1868 assert(s->heap.heap_index[x] < 0);
1869 s->heap.activity[x] = 0.0;
1870
1871 #if 0
1872 printf("bvar %"PRId32": activity = %f\n", x, s->heap.activity[x]);
1873 #endif
1874 heap_insert(&s->heap, x);
1875
1876 l0 = pos_lit(x);
1877 l1 = neg_lit(x);
1878 s->bin[l0] = NULL;
1879 s->bin[l1] = NULL;
1880 s->watch[l0] = NULL_LINK;
1881 s->watch[l1] = NULL_LINK;
1882 }
1883
1884 /*
1885 * Create a fresh variable and return its index
1886 * - the index is x = s->nvars
1887 */
create_boolean_variable(smt_core_t * s)1888 bvar_t create_boolean_variable(smt_core_t *s) {
1889 uint32_t new_size, i;
1890
1891 i = s->nvars;
1892 if (i >= s->vsize) {
1893 new_size = s->vsize + 1;
1894 new_size += new_size >> 1;
1895 extend_smt_core(s, new_size);
1896 assert(i < s->vsize);
1897 }
1898
1899 init_variable(s, i);
1900 s->nvars ++;
1901 s->nlits += 2;
1902
1903 return i;
1904 }
1905
1906 /*
1907 * Add n fresh boolean variables: indices are allocated starting
1908 * from s->nvars (i.e., if s->nvars == v before the call, the
1909 * new variables have indices v, v+1, ... v+n-1).
1910 */
add_boolean_variables(smt_core_t * s,uint32_t n)1911 void add_boolean_variables(smt_core_t *s, uint32_t n) {
1912 uint32_t nv, new_size, i;
1913
1914 nv = s->nvars;
1915 if (nv + n > s->vsize) {
1916 new_size = s->vsize + 1;
1917 new_size += new_size >> 1;
1918 if (new_size < nv + n) {
1919 new_size = nv + n;
1920 }
1921 extend_smt_core(s, new_size);
1922 assert(nv + n <= s->vsize);
1923 }
1924
1925 for (i=nv; i<nv+n; i++) {
1926 init_variable(s, i);
1927 }
1928
1929 s->nvars += n;
1930 s->nlits += 2 * n;
1931 }
1932
1933
1934
1935 /*
1936 * Attach atom a to boolean variable x
1937 * - x must not have an atom attached already
1938 */
attach_atom_to_bvar(smt_core_t * s,bvar_t x,void * atom)1939 void attach_atom_to_bvar(smt_core_t *s, bvar_t x, void *atom) {
1940 atom_table_t *tbl;
1941
1942 tbl = &s->atoms;
1943 if (tbl->size <= x) {
1944 // make atom table as large as s->vsize
1945 resize_atom_table(tbl, s->vsize);
1946 }
1947 add_atom(tbl, x, atom);
1948 }
1949
1950
1951 /*
1952 * Check whether x has an atom attached
1953 */
bvar_has_atom(smt_core_t * s,bvar_t x)1954 bool bvar_has_atom(smt_core_t *s, bvar_t x) {
1955 atom_table_t *tbl;
1956
1957 assert(0 <= x && x < s->nvars);
1958 tbl = &s->atoms;
1959 return x < tbl->size && tst_bit(tbl->has_atom, x);
1960 }
1961
1962
1963 /*
1964 * Return the atom attached to x (NULL if there's none)
1965 */
bvar_atom(smt_core_t * s,bvar_t x)1966 void *bvar_atom(smt_core_t *s, bvar_t x) {
1967 atom_table_t *tbl;
1968
1969 assert(0 <= x && x < s->nvars);
1970 tbl = &s->atoms;
1971 if (x < tbl->size && tst_bit(tbl->has_atom, x)) {
1972 return tbl->atom[x];
1973 } else {
1974 return NULL;
1975 }
1976 }
1977
1978
1979 /*
1980 * Remove atom attached to x
1981 */
remove_bvar_atom(smt_core_t * s,bvar_t x)1982 void remove_bvar_atom(smt_core_t *s, bvar_t x) {
1983 atom_table_t *tbl;
1984
1985 assert(0 <= x && x < s->nvars);
1986 tbl = &s->atoms;
1987 if (x < tbl->size && tst_bit(tbl->has_atom, x)) {
1988 remove_atom(tbl, x);
1989 }
1990 }
1991
1992
1993 /*
1994 * Set the initial activity of variable x
1995 */
set_bvar_activity(smt_core_t * s,bvar_t x,double a)1996 void set_bvar_activity(smt_core_t *s, bvar_t x, double a) {
1997 assert(0 <= x && x < s->nvars && a < DBL_MAX);
1998 heap_remove(&s->heap, x);
1999 s->heap.activity[x] = a;
2000 heap_insert(&s->heap, x);
2001 }
2002
2003
2004
2005
2006
2007 /**************************
2008 * VARIABLE ASSIGNMENTS *
2009 *************************/
2010
2011 /*
2012 * Assign literal l at the base level
2013 */
assign_literal(smt_core_t * s,literal_t l)2014 static void assign_literal(smt_core_t *s, literal_t l) {
2015 bvar_t v;
2016
2017 #if TRACE
2018 printf("---> DPLL: Assigning literal ");
2019 print_literal(stdout, l);
2020 printf(", decision level = %"PRIu32"\n", s->decision_level);
2021 fflush(stdout);
2022 #endif
2023 assert(0 <= l && l < s->nlits);
2024 assert(literal_is_unassigned(s, l));
2025 assert(s->decision_level == s->base_level);
2026
2027 push_literal(&s->stack, l);
2028
2029 v = var_of(l);
2030 s->value[v] = (VAL_TRUE ^ sign_of_lit(l));
2031 s->level[v] = s->base_level;
2032 s->antecedent[v] = mk_literal_antecedent(null_literal);
2033 set_bit(s->mark, v); // assigned at (or below) base_level
2034
2035 assert(literal_value(s, l) == VAL_TRUE && literal_value(s, not(l)) == VAL_FALSE);
2036 }
2037
2038
2039
2040 /*
2041 * Decide literal: increase decision level then
2042 * assign literal l to true and push it on the stack
2043 * - l must not be assigned
2044 */
decide_literal(smt_core_t * s,literal_t l)2045 void decide_literal(smt_core_t *s, literal_t l) {
2046 uint32_t k;
2047 bvar_t v;
2048
2049 assert(s->status == STATUS_SEARCHING || s->status == STATUS_INTERRUPTED);
2050 assert(literal_is_unassigned(s, l));
2051
2052 // Increase decision level
2053 k = s->decision_level + 1;
2054 s->decision_level = k;
2055 if (s->stack.nlevels <= k) {
2056 increase_stack_levels(&s->stack);
2057 }
2058 s->stack.level_index[k] = s->stack.top;
2059
2060 push_literal(&s->stack, l);
2061
2062 v = var_of(l);
2063 s->value[v] = (VAL_TRUE ^ sign_of_lit(l));
2064 s->level[v] = k;
2065 s->antecedent[v] = mk_literal_antecedent(null_literal);
2066
2067 assert(literal_value(s, l) == VAL_TRUE && literal_value(s, not(l)) == VAL_FALSE);
2068
2069 // Notify the theory solver
2070 s->th_ctrl.increase_decision_level(s->th_solver);
2071
2072 s->stats.decisions ++;
2073
2074 #if TRACE
2075 printf("\n---> DPLL: Decision: literal ");
2076 print_literal(stdout, l);
2077 printf(", decision level = %"PRIu32"\n", s->decision_level);
2078 fflush(stdout);
2079 #endif
2080 }
2081
2082
2083 /*
2084 * Assign literal l to true with the given antecedent
2085 * - s->mark[v] is set if decision level = base level
2086 */
implied_literal(smt_core_t * s,literal_t l,antecedent_t a)2087 static void implied_literal(smt_core_t *s, literal_t l, antecedent_t a) {
2088 bvar_t v;
2089
2090 assert(literal_is_unassigned(s, l));
2091
2092 #if TRACE
2093 printf("---> DPLL: Implied literal ");
2094 print_literal(stdout, l);
2095 printf(", decision level = %"PRIu32"\n", s->decision_level);
2096 fflush(stdout);
2097 #endif
2098
2099 s->stats.propagations ++;
2100
2101 push_literal(&s->stack, l);
2102
2103 v = var_of(l);
2104 s->value[v] = (VAL_TRUE ^ sign_of_lit(l));
2105 s->level[v] = s->decision_level;
2106 s->antecedent[v] = a;
2107 if (s->decision_level == s->base_level) {
2108 set_bit(s->mark, v);
2109 s->nb_unit_clauses ++;
2110 }
2111
2112 assert(literal_value(s, l) == VAL_TRUE && literal_value(s, not(l)) == VAL_FALSE);
2113 }
2114
2115
propagate_literal(smt_core_t * s,literal_t l,void * expl)2116 void propagate_literal(smt_core_t *s, literal_t l, void *expl) {
2117 bvar_t v;
2118
2119 assert(literal_is_unassigned(s, l));
2120 assert(bvar_has_atom(s, var_of(l)));
2121
2122 #if TRACE
2123 printf("---> DPLL: Theory prop ");
2124 print_literal(stdout, l);
2125 printf(", decision level = %"PRIu32"\n", s->decision_level);
2126 fflush(stdout);
2127 #endif
2128
2129 s->stats.propagations ++;
2130 s->stats.th_props ++;
2131
2132 push_literal(&s->stack, l);
2133
2134 v = var_of(l);
2135 s->value[v] = (VAL_TRUE ^ sign_of_lit(l));
2136 s->level[v] = s->decision_level;
2137 s->antecedent[v] = mk_generic_antecedent(expl);
2138 if (s->decision_level == s->base_level) {
2139 set_bit(s->mark, v);
2140 s->nb_unit_clauses ++;
2141 }
2142
2143 assert(literal_value(s, l) == VAL_TRUE && literal_value(s, not(l)) == VAL_FALSE);
2144 }
2145
2146
2147
2148
2149 /***************************
2150 * HEURISTICS/ACTIVITIES *
2151 **************************/
2152
2153 /*
2154 * Select an unassigned literal: returns null_literal if all literals
2155 * are assigned. Use activity-based heuristic + randomization.
2156 */
select_unassigned_literal(smt_core_t * s)2157 literal_t select_unassigned_literal(smt_core_t *s) {
2158 uint32_t rnd;
2159 bvar_t x;
2160 uint8_t *v;
2161
2162 #if DEBUG
2163 check_heap(s);
2164 #endif
2165
2166 v = s->value;
2167
2168 if (s->scaled_random > 0) {
2169 rnd = random_uint32(s) & VAR_RANDOM_MASK;
2170 if (rnd < s->scaled_random) {
2171 x = random_uint(s, s->nvars);
2172 assert(0 <= x && x < s->nvars);
2173 if (bval_is_undef(v[x])) {
2174 #if TRACE
2175 printf("---> DPLL: Random selection: variable ");
2176 print_bvar(stdout, x);
2177 printf("\n");
2178 fflush(stdout);
2179 #endif
2180 s->stats.random_decisions ++;
2181 goto var_found;
2182 }
2183 }
2184 }
2185
2186 /*
2187 * select unassigned variable x with highest activity
2188 */
2189 while (! heap_is_empty(&s->heap)) {
2190 x = heap_get_top(&s->heap);
2191 if (bval_is_undef(v[x])) {
2192 goto var_found;
2193 }
2194 }
2195
2196 // empty heap
2197 return null_literal;
2198
2199
2200 var_found:
2201 // if polarity x == 1 use pos_lit(x) otherwise use neg_lit(x)
2202 return mk_signed_lit(x, v[x] & 1);
2203 }
2204
2205
2206
2207 /*
2208 * Get the unassigned variable of highest activity
2209 * return null_bvar if all variables are assigned
2210 */
select_most_active_bvar(smt_core_t * s)2211 bvar_t select_most_active_bvar(smt_core_t *s) {
2212 bvar_t x;
2213 uint8_t *v;
2214
2215 v = s->value;
2216 while (! heap_is_empty(&s->heap)) {
2217 x = heap_get_top(&s->heap);
2218 if (bval_is_undef(v[x])) {
2219 goto var_found;
2220 }
2221 }
2222
2223 x = null_bvar;
2224
2225 var_found:
2226 return x;
2227 }
2228
2229
2230
2231 /*
2232 * Choose an unassigned variable randomly (uniformly)
2233 * return null_bvar if all variables are assigned
2234 */
select_random_bvar(smt_core_t * s)2235 bvar_t select_random_bvar(smt_core_t *s) {
2236 bvar_t x, y;
2237 uint8_t *v;
2238 uint32_t n, d;
2239
2240 v = s->value;
2241 n = s->nvars;
2242 x = random_uint(s, n); // 0 ... n-1
2243 assert(0 <= x && x < n);
2244
2245 if (bval_is_undef(v[x])) return x;
2246
2247 if (all_variables_assigned(s)) return null_bvar;
2248
2249 // d = random increment, must be prime with n.
2250 d = 1 + random_uint(s, n - 1); // 1 ... n-1
2251 while (gcd32(d, n) != 1) d--;
2252
2253 // search in sequence x, x+d, x+2d, ... (modulo n)
2254 y = x;
2255 do {
2256 y += d;
2257 if (y > n) y -= n;
2258 assert(x != y); // don't loop
2259 } while (bval_is_def(v[y]));
2260
2261 return y;
2262 }
2263
2264
2265
2266
2267 /*
2268 * Increase activity of variable x
2269 */
increase_bvar_activity(smt_core_t * s,bvar_t x)2270 static void increase_bvar_activity(smt_core_t *s, bvar_t x) {
2271 int32_t i;
2272 var_heap_t *heap;
2273 #if DEBUG
2274 bool rescaled = false;
2275 #endif
2276
2277 heap = &s->heap;
2278 if ((heap->activity[x] += heap->act_increment) > VAR_ACTIVITY_THRESHOLD) {
2279 rescale_var_activities(heap, s->nvars);
2280 #if DEBUG
2281 rescaled = true;
2282 #endif
2283 }
2284
2285 // move x up if it's in the heap
2286 i = heap->heap_index[x];
2287 if (i >= 0) {
2288 update_up(heap, x, i);
2289 }
2290
2291 #if DEBUG
2292 if (rescaled) {
2293 check_heap(s);
2294 }
2295 #endif
2296
2297 }
2298
2299
2300
2301 /***********************
2302 * CLAUSE ACTIVITIES *
2303 **********************/
2304
2305 /*
2306 * Rescale activity of all the learned clauses
2307 * (divide all by CLAUSE_ACTIVITY_THRESHOLD)
2308 */
rescale_clause_activities(smt_core_t * s)2309 static void rescale_clause_activities(smt_core_t *s) {
2310 uint32_t i, n;
2311 clause_t **v;
2312
2313 s->cla_inc *= INV_CLAUSE_ACTIVITY_THRESHOLD;
2314 v = s->learned_clauses;
2315 n = get_cv_size(v);
2316 for (i=0; i<n; i++) {
2317 multiply_activity(v[i], INV_CLAUSE_ACTIVITY_THRESHOLD);
2318 }
2319 }
2320
2321
2322 /*
2323 * Increase activity of learned clause cl
2324 */
increase_clause_activity(smt_core_t * s,clause_t * cl)2325 static void increase_clause_activity(smt_core_t *s, clause_t *cl) {
2326 increase_activity(cl, s->cla_inc);
2327 if (get_activity(cl) > CLAUSE_ACTIVITY_THRESHOLD) {
2328 rescale_clause_activities(s);
2329 }
2330 }
2331
2332
2333
2334
2335 /*******************
2336 * BACKTRACKING *
2337 ******************/
2338
2339 /*
2340 * Backtrack core to decision level back_level
2341 * - undo all literal assignments of level >= back_level + 1
2342 * - requires decision_level > back_level >= base_level
2343 * Also clear conflict data and sets cp_flag if deletion of atoms is enabled
2344 *
2345 * NOTE: this function does not force the theory solver to backtrack.
2346 */
backtrack(smt_core_t * s,uint32_t back_level)2347 static void backtrack(smt_core_t *s, uint32_t back_level) {
2348 uint32_t i, k;
2349 literal_t *u, l;
2350 bvar_t x;
2351
2352 #if TRACE
2353 printf("---> DPLL: Backtracking to level %"PRIu32"\n\n", back_level);
2354 fflush(stdout);
2355 #endif
2356
2357 assert(s->base_level <= back_level && back_level < s->decision_level);
2358
2359 u = s->stack.lit;
2360 k = s->stack.level_index[back_level + 1];
2361 i = s->stack.top;
2362 while (i > k) {
2363 i --;
2364 l = u[i];
2365
2366 assert(literal_value(s, l) == VAL_TRUE);
2367 assert(s->level[var_of(l)] > back_level);
2368
2369 // clear assignment of x, keep polarity bit
2370 x = var_of(l);
2371 s->value[x] &= 1;
2372 heap_insert(&s->heap, x);
2373
2374 assert(literal_value(s, l) == VAL_UNDEF_TRUE);
2375 }
2376
2377 s->stack.top = i;
2378 s->stack.prop_ptr = i;
2379 s->stack.theory_ptr = i;
2380 s->decision_level = back_level;
2381
2382 // Update the cp_flag: the deletion of atoms is enabled if there's a checkpoint
2383 // and if the top checkpoint has level >= the new decision level
2384 s->cp_flag = non_empty_checkpoint_stack(&s->checkpoints) &&
2385 top_checkpoint(&s->checkpoints)->dlevel >= back_level;
2386
2387 // adust the assumption index
2388 k = back_level - s->base_level;
2389 if (k < s->assumption_index) {
2390 s->assumption_index = k;
2391 }
2392 }
2393
2394
2395
2396 /*
2397 * Cause both s and the theory solver to backtrack
2398 */
backtrack_to_level(smt_core_t * s,uint32_t back_level)2399 static void backtrack_to_level(smt_core_t *s, uint32_t back_level) {
2400 if (back_level < s->decision_level) {
2401 backtrack(s, back_level);
2402 s->th_ctrl.backtrack(s->th_solver, back_level);
2403 }
2404 }
2405
backtrack_to_base_level(smt_core_t * s)2406 static void backtrack_to_base_level(smt_core_t *s) {
2407 backtrack_to_level(s, s->base_level);
2408 }
2409
2410
2411 /***************
2412 * CONFLICTS *
2413 **************/
2414
2415 /*
2416 * Record a two-literal conflict: clause {l0, l1} is false
2417 */
record_binary_conflict(smt_core_t * s,literal_t l0,literal_t l1)2418 static void record_binary_conflict(smt_core_t *s, literal_t l0, literal_t l1) {
2419 #if TRACE
2420 printf("\n---> DPLL: Binary conflict: {");
2421 print_literal(stdout, l0);
2422 printf(", ");
2423 print_literal(stdout, l1);
2424 printf("}\n");
2425 fflush(stdout);
2426 #endif
2427
2428 assert(! s->theory_conflict);
2429
2430 s->inconsistent = true;
2431 s->conflict_buffer[0] = l0;
2432 s->conflict_buffer[1] = l1;
2433 s->conflict_buffer[2] = end_clause;
2434 s->conflict = s->conflict_buffer;
2435 }
2436
2437
2438 /*
2439 * Record cl as a conflict clause
2440 */
record_clause_conflict(smt_core_t * s,clause_t * cl)2441 static void record_clause_conflict(smt_core_t *s, clause_t *cl) {
2442 #if TRACE
2443 uint32_t i;
2444 literal_t ll;
2445
2446 printf("\n---> DPLL: Conflict: {");
2447 print_literal(stdout, get_first_watch(cl));
2448 printf(", ");
2449 print_literal(stdout, get_second_watch(cl));
2450 i = 2;
2451 ll = cl->cl[i];
2452 while (ll >= 0) {
2453 printf(", ");
2454 print_literal(stdout, ll);
2455 i++;
2456 ll = cl->cl[i];
2457 }
2458 printf("}\n");
2459 fflush(stdout);
2460 #endif
2461
2462 assert(! s->theory_conflict);
2463
2464 s->inconsistent = true;
2465 s->false_clause = cl;
2466 s->conflict = cl->cl;
2467 }
2468
2469
2470 /*
2471 * Externally generated conflict (i.e., by a theory solver)
2472 * - a must be an array of literals terminated by null_literal
2473 * - all literals in a must be false in the current assignment
2474 */
record_theory_conflict(smt_core_t * s,literal_t * a)2475 void record_theory_conflict(smt_core_t *s, literal_t *a) {
2476 #if TRACE
2477 uint32_t i;
2478 literal_t l;
2479
2480 printf("---> DPLL: Theory conflict: {");
2481 i = 0;
2482 l = a[i];
2483 if (l >= 0) {
2484 print_literal(stdout, l);
2485 i ++;
2486 l = a[i];
2487 while (l >= 0) {
2488 printf(", ");
2489 print_literal(stdout, l);
2490 i++;
2491 l = a[i];
2492 }
2493 }
2494 printf("}\n");
2495 #endif
2496 fflush(stdout);
2497
2498 #if DEBUG
2499 check_theory_conflict(s, a);
2500 #endif
2501
2502 assert(! s->inconsistent && ! s->theory_conflict);
2503 s->stats.th_conflicts ++;
2504 s->inconsistent = true;
2505 s->theory_conflict = true;
2506 s->false_clause = NULL;
2507 s->conflict = a;
2508 }
2509
2510
2511 /*
2512 * Short cuts
2513 */
record_empty_theory_conflict(smt_core_t * s)2514 void record_empty_theory_conflict(smt_core_t *s) {
2515 s->conflict_buffer[0] = null_literal;
2516 record_theory_conflict(s, s->conflict_buffer);
2517 }
2518
record_unit_theory_conflict(smt_core_t * s,literal_t l)2519 void record_unit_theory_conflict(smt_core_t *s, literal_t l) {
2520 s->conflict_buffer[0] = l;
2521 s->conflict_buffer[1] = null_literal;
2522 record_theory_conflict(s, s->conflict_buffer);
2523 }
2524
record_binary_theory_conflict(smt_core_t * s,literal_t l1,literal_t l2)2525 void record_binary_theory_conflict(smt_core_t *s, literal_t l1, literal_t l2) {
2526 s->conflict_buffer[0] = l1;
2527 s->conflict_buffer[1] = l2;
2528 s->conflict_buffer[2] = null_literal;
2529 record_theory_conflict(s, s->conflict_buffer);
2530 }
2531
record_ternary_theory_conflict(smt_core_t * s,literal_t l1,literal_t l2,literal_t l3)2532 void record_ternary_theory_conflict(smt_core_t *s, literal_t l1, literal_t l2, literal_t l3) {
2533 s->conflict_buffer[0] = l1;
2534 s->conflict_buffer[1] = l2;
2535 s->conflict_buffer[2] = l3;
2536 s->conflict_buffer[3] = null_literal;
2537 record_theory_conflict(s, s->conflict_buffer);
2538 }
2539
2540
2541
2542 /*************************
2543 * BOOLEAN PROPAGATION *
2544 ************************/
2545
2546 /*
2547 * Short cut: lit_val(v, l) is value of l
2548 * - v must be equal to solver->value
2549 */
lit_val(uint8_t * v,literal_t l)2550 static inline bval_t lit_val(uint8_t *v, literal_t l) {
2551 return v[var_of(l)] ^ sign_of_lit(l);
2552 }
2553
2554 /*
2555 * Propagation via binary clauses:
2556 * - val = literal value array (must be s->value)
2557 * - l0 = literal (must be false in the current assignment)
2558 * - v = array of literals terminated by -1 (must be s->bin[l])
2559 * v must be != NULL
2560 *
2561 * Return true if there's no conflict, false otherwise.
2562 */
propagation_via_bin_vector(smt_core_t * s,uint8_t * val,literal_t l0,literal_t * v)2563 static bool propagation_via_bin_vector(smt_core_t *s, uint8_t *val, literal_t l0, literal_t *v) {
2564 literal_t l1;
2565 bval_t v1;
2566
2567 assert(v != NULL);
2568 assert(s->value == val && s->bin[l0] == v && literal_value(s, l0) == VAL_FALSE);
2569
2570 for (;;) {
2571 // Search for non-true literals in v
2572 // This terminates since val[end_marker] = VAL_UNDEF
2573 do {
2574 l1 = *v ++;
2575 v1 = lit_val(val, l1);
2576 } while (v1 == VAL_TRUE);
2577
2578 if (l1 < 0) break; // end_marker
2579
2580 if (bval_is_undef(v1)) {
2581 implied_literal(s, l1, mk_literal_antecedent(l0));
2582 } else {
2583 record_binary_conflict(s, l0, l1);
2584 return false;
2585 }
2586 }
2587
2588 return true;
2589 }
2590
2591
2592
2593 /*
2594 * Propagation via the watched lists of a literal l0.
2595 * - val = literal value array (must be s->value)
2596 *
2597 * Return true if there's no conflict, false otherwise
2598 */
propagation_via_watched_list(smt_core_t * s,uint8_t * val,literal_t l0)2599 static bool propagation_via_watched_list(smt_core_t *s, uint8_t *val, literal_t l0) {
2600 clause_t *cl;
2601 link_t *list;
2602 link_t link;
2603 bval_t v1;
2604 uint32_t k, i;
2605 literal_t l1, l, *b;
2606
2607 assert(s->value == val);
2608
2609 list = &s->watch[l0];
2610 link = *list;
2611 while (link != NULL_LINK) {
2612 cl = clause_of(link);
2613 i = idx_of(link);
2614 l1 = get_other_watch(cl, i);
2615 v1 = lit_val(val, l1);
2616
2617 assert(next_of(link) == cl->link[i]);
2618 assert(cdr_ptr(link) == cl->link + i);
2619
2620 if (v1 == VAL_TRUE) {
2621 /*
2622 * Skip clause cl: it's already true
2623 */
2624 *list = link;
2625 list = cl->link + i;
2626 link = cl->link[i];
2627
2628 } else {
2629 /*
2630 * Search for a new watched literal in cl.
2631 * The loop terminates since cl->cl terminates with an end marked
2632 * and val[end_marker] == VAL_UNDEF.
2633 */
2634 k = 1;
2635 b = cl->cl;
2636 do {
2637 k ++;
2638 l = b[k];
2639 } while (lit_val(val, l) == VAL_FALSE);
2640
2641 if (l >= 0) {
2642 /*
2643 * l occurs in b[k] = cl->cl[k] and is either TRUE or UNDEF
2644 * make l a new watched literal
2645 * - swap b[i] and b[k]
2646 * - insert cl into l's watched list (link[i])
2647 */
2648 b[k] = b[i];
2649 b[i] = l;
2650
2651 // insert cl in watch[l] list and move to the next clause
2652 link = cl->link[i];
2653 s->watch[l] = cons(i, cl, s->watch[l]);
2654 } else {
2655 /*
2656 * All literals of cl, except possibly l1, are false
2657 */
2658 if (bval_is_undef(v1)) {
2659 // l1 is implied
2660 implied_literal(s, l1, mk_clause_antecedent(cl, i^1));
2661
2662 // move to the next clause
2663 *list = link;
2664 list = cl->link + i;
2665 link = cl->link[i];
2666
2667 } else {
2668 // v1 == VAL_FALSE: conflict found
2669 record_clause_conflict(s, cl);
2670 *list = link;
2671 return false;
2672 }
2673 }
2674 }
2675 }
2676
2677 *list = NULL_LINK;
2678
2679 return true;
2680 }
2681
2682
2683
2684 /*
2685 * Full boolean propagation: until either the propagation queue is empty,
2686 * or a conflict is found
2687 * - result = true if no conflict, false otherwise
2688 */
boolean_propagation(smt_core_t * s)2689 static bool boolean_propagation(smt_core_t *s) {
2690 uint8_t *val;
2691 literal_t l, *bin;
2692 uint32_t i;
2693
2694 val = s->value;
2695
2696 for (i = s->stack.prop_ptr; i < s->stack.top; i++) {
2697 l = not(s->stack.lit[i]);
2698
2699 bin = s->bin[l];
2700 if (bin != NULL && ! propagation_via_bin_vector(s, val, l, bin)) {
2701 // conflict found
2702 return false;
2703 }
2704
2705 if (! propagation_via_watched_list(s, val, l)) {
2706 return false;
2707 }
2708 }
2709
2710 s->stack.prop_ptr = i;
2711
2712 #if DEBUG
2713 check_propagation(s);
2714 #endif
2715
2716 return true;
2717 }
2718
2719
2720
2721 /**************************************
2722 * PROPAGATION TO THE THEORY SOLVER *
2723 *************************************/
2724
2725 /*
2726 * Propagate all atom assignments to the theory solver
2727 * - return true if no conflict is found
2728 * - return false otherwise
2729 */
theory_propagation(smt_core_t * s)2730 static bool theory_propagation(smt_core_t *s) {
2731 uint32_t i, n;
2732 byte_t *has_atom;
2733 void **atom;
2734 literal_t *queue;
2735 literal_t l;
2736 bvar_t x;
2737
2738 /*
2739 * IMPORTANT: make sure the theory_solver does not
2740 * create new atoms within the assert_atom function
2741 */
2742 n = s->atoms.size;
2743 has_atom = s->atoms.has_atom;
2744 atom = s->atoms.atom;
2745 queue = s->stack.lit;
2746
2747 for (i = s->stack.theory_ptr; i < s->stack.top; i++) {
2748 l = queue[i];
2749 x = var_of(l);
2750 if (x < n && tst_bit(has_atom, x)) {
2751 if (! s->th_smt.assert_atom(s->th_solver, atom[x], l)) {
2752 // theory conflict reported
2753 // assert(s->inconsistent && s->theory_conflict);
2754 /*
2755 * HACK: Changed this assert because the bvsolver adds the empty clause
2756 * rather than create a theory conflict.
2757 */
2758 assert(s->inconsistent);
2759 return false;
2760 }
2761 }
2762 }
2763
2764 s->stack.theory_ptr = i;
2765
2766 /*
2767 * If this function is called at base_level, then the theory solver
2768 * may add clauses (in its propagate function). In particular, the
2769 * theory solver may add the empty clause, which sets
2770 * s->inconsistent to true. So we must check for s->inconsistent
2771 * here.
2772 */
2773 return s->th_ctrl.propagate(s->th_solver) && !s->inconsistent;
2774 }
2775
2776
2777
2778 /************************
2779 * FULL PROPAGATION *
2780 ***********************/
2781
2782 /*
2783 * Propagate all boolean assignments and all atoms,
2784 * repeat if the theory solver has implied some literals
2785 * - return false if a conflict is detected
2786 * - return true otherwise
2787 */
smt_propagation(smt_core_t * s)2788 static bool smt_propagation(smt_core_t *s) {
2789 bool code;
2790 uint32_t n;
2791
2792 if (s->bool_only) {
2793 // purely boolean problem
2794 return boolean_propagation(s);
2795 }
2796
2797 do {
2798 code = boolean_propagation(s);
2799 if (! code) break;
2800 n = s->stack.top;
2801 code = theory_propagation(s);
2802 } while (code && n < s->stack.top);
2803
2804 return code;
2805 }
2806
2807
2808
2809
2810 /***********************************
2811 * MARKS FOR CONFLICT RESOLUTION *
2812 **********************************/
2813
is_var_unmarked(smt_core_t * s,bvar_t x)2814 static inline bool is_var_unmarked(smt_core_t *s, bvar_t x) {
2815 return ! tst_bit(s->mark, x);
2816 }
2817
2818 #if DEBUG || !defined(NDEBUG)
is_var_marked(smt_core_t * s,bvar_t x)2819 static inline bool is_var_marked(smt_core_t *s, bvar_t x) {
2820 return tst_bit(s->mark, x);
2821 }
2822 #endif
2823
set_var_mark(smt_core_t * s,bvar_t x)2824 static inline void set_var_mark(smt_core_t *s, bvar_t x) {
2825 set_bit(s->mark, x);
2826 }
2827
clr_var_mark(smt_core_t * s,bvar_t x)2828 static inline void clr_var_mark(smt_core_t *s, bvar_t x) {
2829 clr_bit(s->mark, x);
2830 }
2831
2832
is_lit_unmarked(smt_core_t * s,literal_t l)2833 static inline bool is_lit_unmarked(smt_core_t *s, literal_t l) {
2834 return ! tst_bit(s->mark, var_of(l));
2835 }
2836
is_lit_marked(smt_core_t * s,literal_t l)2837 static inline bool is_lit_marked(smt_core_t *s, literal_t l) {
2838 return tst_bit(s->mark, var_of(l));
2839 }
2840
set_lit_mark(smt_core_t * s,literal_t l)2841 static inline void set_lit_mark(smt_core_t *s, literal_t l) {
2842 set_bit(s->mark, var_of(l));
2843 }
2844
clear_lit_mark(smt_core_t * s,literal_t l)2845 static inline void clear_lit_mark(smt_core_t *s, literal_t l) {
2846 clr_bit(s->mark, var_of(l));
2847 }
2848
2849
2850 /*
2851 * Decision level for assigned literal l
2852 */
d_level(smt_core_t * s,literal_t l)2853 static inline uint32_t d_level(smt_core_t *s, literal_t l) {
2854 return s->level[var_of(l)];
2855 }
2856
2857
2858
2859 /*********************
2860 * LEARNED CLAUSES *
2861 ********************/
2862
2863 /*
2864 * Auxiliary function: add { l1, l2} as a binary clause
2865 * - l1 and l2 must be distinct (and not complementary)
2866 * - we put the function here because it's used by add_learned_clause
2867 */
direct_binary_clause(smt_core_t * s,literal_t l1,literal_t l2)2868 static void direct_binary_clause(smt_core_t *s, literal_t l1, literal_t l2) {
2869 #if TRACE
2870 printf("---> DPLL: Add binary clause: { ");
2871 print_literal(stdout, l1);
2872 printf(" ");
2873 print_literal(stdout, l2);
2874 printf(" }\n");
2875 fflush(stdout);
2876 #endif
2877
2878 add_literal_to_vector(s->bin + l1, l2);
2879 add_literal_to_vector(s->bin + l2, l1);
2880 s->nb_bin_clauses ++;
2881
2882 if (s->base_level > 0) {
2883 // make a copy for push/pop
2884 ivector_push(&s->binary_clauses, l1);
2885 ivector_push(&s->binary_clauses, l2);
2886 }
2887 }
2888
2889
2890 /*
2891 * Add an array of literals a as a new learned clause, after conflict resolution.
2892 * - n must be at least 1
2893 * - all literals must be assigned to false
2894 * - a[0] must be the implied literal: all other literals must have
2895 * a lower assignment level than a[0].
2896 * - backtrack to the decision_level where a[0] is implied, then
2897 * add a[0] to the propagation queue
2898 */
add_learned_clause(smt_core_t * s,uint32_t n,literal_t * a)2899 static void add_learned_clause(smt_core_t *s, uint32_t n, literal_t *a) {
2900 clause_t *cl;
2901 uint32_t i, j, k, q;
2902 literal_t l0, l1;
2903
2904 #if TRACE
2905 printf("---> DPLL: Learned clause: {");
2906 for (i=0; i<n; i++) {
2907 printf(" ");
2908 print_literal(stdout, a[i]);
2909 }
2910 printf(" }\n\n");
2911 fflush(stdout);
2912 #endif
2913
2914 l0 = a[0];
2915
2916 if (n == 1) {
2917
2918 backtrack_to_base_level(s);
2919 if (literal_value(s, l0) == VAL_FALSE) {
2920 // conflict (the whole thing is unsat)
2921 s->inconsistent = true;
2922 s->conflict = s->conflict_buffer;
2923 s->conflict_buffer[0] = l0;
2924 s->conflict_buffer[1] = end_clause;
2925 } else {
2926 #if TRACE
2927 printf("---> DPLL: Add learned unit clause: { ");
2928 print_literal(stdout, l0);
2929 printf(" }\n");
2930 fflush(stdout);
2931 #endif
2932 assign_literal(s, l0);
2933 s->nb_unit_clauses ++;
2934 }
2935
2936 } else if (n == 2) {
2937
2938 l1 = a[1];
2939 k = s->level[var_of(l1)];
2940 assert(k < s->level[var_of(l0)]);
2941
2942 direct_binary_clause(s, l0, l1);
2943 backtrack_to_level(s, k);
2944 implied_literal(s, l0, mk_literal_antecedent(l1));
2945
2946 } else {
2947
2948 // EXPERIMENTAL
2949 // if (s->etable != NULL) {
2950 // test_eq_clause(s, "after simplification", n, a);
2951 // }
2952
2953 // find literal of second highest level in a[0 ... n-1]
2954 j = 1;
2955 k = s->level[var_of(a[1])];
2956 for (i=2; i<n; i++) {
2957 q = s->level[var_of(a[i])];
2958 if (q > k) {
2959 k = q;
2960 j = i;
2961 }
2962 }
2963
2964 // swap a[1] and a[j]
2965 l1 = a[j]; a[j] = a[1]; a[1] = l1;
2966
2967 // create the new clause with l0 and l1 as watched literals
2968 cl = new_learned_clause(n, a);
2969 add_clause_to_vector(&s->learned_clauses, cl);
2970 increase_clause_activity(s, cl);
2971
2972 // add cl at the start of watch[l0] and watch[l1]
2973 s->watch[l0] = cons(0, cl, s->watch[l0]);
2974 s->watch[l1] = cons(1, cl, s->watch[l1]);
2975
2976 s->nb_clauses ++;
2977 s->stats.learned_literals += n;
2978
2979 // backtrack and assert l0
2980 assert(k < s->level[var_of(l0)]);
2981 backtrack_to_level(s, k);
2982
2983 implied_literal(s, l0, mk_clause0_antecedent(cl));
2984 }
2985 }
2986
2987
2988 /*
2989 * Auxiliary function: attempt to add a[0] ... a[n-1] as a learned clause
2990 * - search for two literals of decision_level == s->decision level then
2991 * use them as watched literals.
2992 * - if such literals can't be found don't do anything
2993 * Return true if the clause was added/false otherwise
2994 */
try_cache_theory_clause(smt_core_t * s,uint32_t n,literal_t * a)2995 static bool try_cache_theory_clause(smt_core_t *s, uint32_t n, literal_t *a) {
2996 clause_t *cl;
2997 uint32_t i, j, d;
2998 literal_t l, l0, l1;
2999
3000 d = s->decision_level;
3001
3002 if (n == 2) {
3003 // add as binary clause
3004 if (d_level(s, a[0]) == d && d_level(s, a[1]) == d) {
3005 direct_binary_clause(s, a[0], a[1]);
3006
3007 #if TRACE
3008 printf("---> DPLL: cached theory clause: { ");
3009 print_literal(stdout, a[0]);
3010 printf(" ");
3011 print_literal(stdout, a[1]);
3012 printf(" }\n");
3013 fflush(stdout);
3014 #endif
3015 return true;
3016 }
3017
3018 return false;
3019
3020 } else if (n > 2) {
3021
3022 i = 0;
3023 while (i<n) {
3024 l = a[i];
3025 if (d_level(s, l) == d) goto found0;
3026 i ++;
3027 }
3028 return false;
3029
3030 found0:
3031 j = i;
3032 l0 = l; // l0 == a[j] == first watched literal
3033 i ++;
3034 while (i<n) {
3035 l = a[i];
3036 if (d_level(s, l) == d) goto found1;
3037 i ++;
3038 }
3039 return false;
3040
3041 found1:
3042 l1 = l; // l1 == a[i] == second watched literal
3043
3044 assert(l0 != l1 && j < i && d_level(s, l0) == d && d_level(s, l1) == d);
3045
3046 // swap a[0] and a[j] == l0, swap a[1] and a[i] == l1
3047 a[j] = a[0]; a[0] = l0;
3048 a[i] = a[1]; a[1] = l1;
3049
3050 #if TRACE
3051 printf("---> DPLL: cached theory clause: {");
3052 for (i=0; i<n; i++) {
3053 printf(" ");
3054 print_literal(stdout, a[i]);
3055 }
3056 printf(" }\n");
3057 fflush(stdout);
3058 #endif
3059
3060 // create the new clause with l0 and l1 as watched literals
3061 cl = new_learned_clause(n, a);
3062 add_clause_to_vector(&s->learned_clauses, cl);
3063 increase_clause_activity(s, cl);
3064
3065 // insert cl at the head of watch[l0] and watch[l1]
3066 s->watch[l0] = cons(0, cl, s->watch[l0]);
3067 s->watch[l1] = cons(1, cl, s->watch[l1]);
3068
3069 s->nb_clauses ++;
3070 s->stats.learned_literals += n;
3071 return true;
3072 }
3073
3074 return false;
3075 }
3076
3077
3078 /*
3079 * Attempt to add a theory conflict as a learned clause
3080 * - a = array of literals
3081 * - n = size of the array
3082 * - all literals a[0] ... a[n-1] must be false
3083 * The clause is added if we can find two literals of level == s->decision_level.
3084 * Uses s->buffer2.
3085 */
try_cache_theory_conflict(smt_core_t * s,uint32_t n,literal_t * a)3086 static void try_cache_theory_conflict(smt_core_t *s, uint32_t n, literal_t *a) {
3087 ivector_t *v;
3088 uint32_t i;
3089 literal_t l;
3090
3091 if (n < 2 || n > s->th_cache_cl_size) return;
3092
3093 v = &s->buffer2;
3094 assert(v->size == 0);
3095
3096 // remove literals false at the base level
3097 for (i=0; i<n; i++) {
3098 l = a[i];
3099 assert(literal_value(s, l) == VAL_FALSE && d_level(s, l) <= s->decision_level);
3100 if (d_level(s, l) > s->base_level) {
3101 ivector_push(v, l);
3102 }
3103 }
3104
3105 // remove duplicate literals then try to add
3106 ivector_remove_duplicates(v);
3107 if (try_cache_theory_clause(s, v->size, v->data)) {
3108 s->stats.th_conflict_lemmas ++;
3109 }
3110
3111 ivector_reset(v);
3112 }
3113
3114
3115
3116 /*
3117 * Attempt to add a theory implication "(a[0] and ... and a[n-1]) implies l0"
3118 * as a learned clause.
3119 * - a[0] ... a[n-1] and l0 must all be true
3120 * - l0 must be assigned with level == current decision level
3121 * The clause is added if we can find another literal of that level among a[0 .. n-1].
3122 * Uses s->buffer2.
3123 */
try_cache_theory_implication(smt_core_t * s,uint32_t n,literal_t * a,literal_t l0)3124 static void try_cache_theory_implication(smt_core_t *s, uint32_t n, literal_t *a, literal_t l0) {
3125 ivector_t *v;
3126 uint32_t i;
3127 literal_t l;
3128
3129 if (n == 0 || n >= s->th_cache_cl_size) return;
3130
3131 v = &s->buffer2;
3132 assert(v->size == 0);
3133
3134 assert(d_level(s, l0) == s->decision_level && literal_value(s, l0) == VAL_TRUE);
3135 ivector_push(v, l0);
3136
3137 // turn the implication into a clause
3138 // ignore literals assigned at the base level
3139 for (i=0; i<n; i++) {
3140 l = a[i];
3141 assert(literal_value(s, l) == VAL_TRUE && d_level(s, l) <= s->decision_level);
3142 if (d_level(s, l) > s->base_level) {
3143 ivector_push(v, not(l));
3144 }
3145 }
3146
3147 // now v->data contains l0 or (not a[0]) or ... or (not a[n-1])
3148 ivector_remove_duplicates(v);
3149 if (try_cache_theory_clause(s, v->size, v->data)) {
3150 s->stats.th_prop_lemmas ++;
3151 }
3152
3153 ivector_reset(v);
3154 }
3155
3156
3157
3158 /**************************************
3159 * CONFLICT ANALYSIS AND RESOLUTION *
3160 *************************************/
3161
3162 /*
3163 * Turn a generic antecedent into a conjunction of literals:
3164 * - store the literals in s->explanation
3165 *
3166 * IMPORTANT: the theory solver must ensure causality. All literals in s->explanation
3167 * must be before l in the assignment/propagation stack.
3168 */
explain_antecedent(smt_core_t * s,literal_t l,antecedent_t a)3169 static void explain_antecedent(smt_core_t *s, literal_t l, antecedent_t a) {
3170 assert(literal_value(s, l) == VAL_TRUE && a == s->antecedent[var_of(l)] &&
3171 antecedent_tag(a) == generic_tag);
3172
3173 ivector_reset(&s->explanation);
3174 s->th_smt.expand_explanation(s->th_solver, l, generic_antecedent(a), &s->explanation);
3175
3176 #if DEBUG
3177 check_theory_explanation(s, l);
3178 #endif
3179 }
3180
3181
3182 /*
3183 * Auxiliary function to accelerate clause simplification (cf. Minisat).
3184 * This builds a hash of the decision levels in a literal array.
3185 * b = array of literals
3186 * n = number of literals
3187 */
signature(smt_core_t * s,literal_t * b,uint32_t n)3188 static uint32_t signature(smt_core_t *s, literal_t *b, uint32_t n) {
3189 uint32_t i, u;
3190
3191 u = 0;
3192 for (i=0; i<n; i++) {
3193 u |= ((uint32_t) 1) << (d_level(s, b[i]) & 31);
3194 }
3195 return u;
3196 }
3197
3198 /*
3199 * Check whether decision level for literal l matches the hash sgn
3200 */
check_level(smt_core_t * s,literal_t l,uint32_t sgn)3201 static inline bool check_level(smt_core_t *s, literal_t l, uint32_t sgn) {
3202 return (sgn & (((uint32_t) 1) << (d_level(s, l) & 31))) != 0;
3203 }
3204
3205
3206 /*
3207 * Analyze literal antecedents of not(l) to check whether l is subsumed.
3208 * - sgn = signature of the learned clause
3209 * level of l must match sgn (i.e., check_level(sol, l, sgn) is not 0).
3210 *
3211 * - returns false if l is not subsumed: either because not(l) has no antecedents
3212 * or if an antecedent of not(l) has a decision level that does not match sgn.
3213 * - returns true otherwise.
3214 *
3215 * Unmarked antecedents are marked and pushed into sol->buffer2.
3216 */
analyze_antecedents(smt_core_t * s,literal_t l,uint32_t sgn)3217 static bool analyze_antecedents(smt_core_t *s, literal_t l, uint32_t sgn) {
3218 bvar_t x;
3219 antecedent_t a;
3220 literal_t l1;
3221 uint32_t i;
3222 ivector_t *b;
3223 literal_t *c;
3224
3225 x = var_of(l);
3226 a = s->antecedent[x];
3227 if (a == mk_literal_antecedent(null_literal)) {
3228 return false;
3229 }
3230
3231 b = &s->buffer2;
3232 switch (antecedent_tag(a)) {
3233 case clause0_tag:
3234 case clause1_tag:
3235 c = clause_antecedent(a)->cl;
3236 i = clause_index(a);
3237 assert(c[i] == not(l));
3238 // other watched literal
3239 l1 = c[i^1];
3240 if (is_lit_unmarked(s, l1)) {
3241 // l1 has the same decision level as l so there's no need to call check_level
3242 set_lit_mark(s, l1);
3243 ivector_push(b, l1);
3244 }
3245 // rest of the clause
3246 i = 2;
3247 l1 = c[i];
3248 while (l1 >= 0) {
3249 if (is_lit_unmarked(s, l1)) {
3250 if (check_level(s, l1, sgn)) {
3251 set_lit_mark(s, l1);
3252 ivector_push(b, l1);
3253 } else {
3254 return false;
3255 }
3256 }
3257 i ++;
3258 l1 = c[i];
3259 }
3260 break;
3261
3262 case literal_tag:
3263 l1 = literal_antecedent(a);
3264 if (is_lit_unmarked(s, l1)) {
3265 set_lit_mark(s, l1);
3266 ivector_push(b, l1);
3267 }
3268 break;
3269
3270 case generic_tag:
3271 /*
3272 * TODO: check whether skipping all theory-propagated literals
3273 * makes a difference here.
3274 */
3275 if (false) {
3276 explain_antecedent(s, not(l), a);
3277 c = s->explanation.data;
3278 // (and c[0] ... c[n-1]) implies (not l)
3279 for (i=0; i<s->explanation.size; i++) {
3280 l1 = not(c[i]);
3281 if (is_lit_unmarked(s, l1)) {
3282 if (check_level(s, l1, sgn)) {
3283 set_lit_mark(s, l1);
3284 ivector_push(b, l1);
3285 } else {
3286 return false;
3287 }
3288 }
3289 }
3290 } else {
3291 return false;
3292 }
3293 break;
3294 }
3295
3296 return true;
3297 }
3298
3299
3300 /*
3301 * Check whether literal l is subsumed by other marked literals
3302 * - sgn = signature of the learned clause (in which l occurs)
3303 * s->buffer2 is used as a queue
3304 */
subsumed(smt_core_t * s,literal_t l,uint32_t sgn)3305 static bool subsumed(smt_core_t *s, literal_t l, uint32_t sgn) {
3306 uint32_t i, n;
3307 ivector_t *b;
3308
3309 b = &s->buffer2;
3310 n = b->size;
3311 i = n;
3312 while (analyze_antecedents(s, l, sgn)) {
3313 if (i < b->size) {
3314 l = b->data[i];
3315 i ++;
3316 } else {
3317 return true;
3318 }
3319 }
3320
3321 // cleanup
3322 for (i=n; i<b->size; i++) {
3323 clear_lit_mark(s, b->data[i]);
3324 }
3325 b->size = n;
3326
3327 return false;
3328 }
3329
3330
3331 /*
3332 * Simplification of a learned clause
3333 * - the clause is stored in s->buffer as an array of literals
3334 * - s->buffer[0] is the implied literal
3335 */
simplify_learned_clause(smt_core_t * s)3336 static void simplify_learned_clause(smt_core_t *s) {
3337 uint32_t hash;
3338 literal_t *b;
3339 literal_t l;
3340 uint32_t i, j, n;
3341
3342 b = s->buffer.data;
3343 n = s->buffer.size;
3344 hash = signature(s, b+1, n-1); // skip b[0]. It cannot subsume anything.
3345
3346 assert(s->buffer2.size == 0);
3347
3348 #if TRACE
3349 printf("---> DPLL: Learned clause: {");
3350 for (i=0; i<n; i++) {
3351 printf(" ");
3352 print_literal(stdout, b[i]);
3353 }
3354 printf(" }\n");
3355 fflush(stdout);
3356 #endif
3357
3358 // remove the subsumed literals
3359 j = 1;
3360 for (i=1; i<n; i++) {
3361 l = b[i];
3362 if (subsumed(s, l, hash)) {
3363 // Hack: move l to buffer2 to clear its mark later
3364 ivector_push(&s->buffer2, l);
3365 } else {
3366 // keep l in buffer
3367 b[j] = l;
3368 j ++;
3369 }
3370 }
3371
3372 s->stats.literals_before_simpl += n;
3373 s->stats.subsumed_literals += n - j;
3374 s->buffer.size = j;
3375
3376 // remove the marks of literals in learned clause
3377 for (i=0; i<j; i++) {
3378 clear_lit_mark(s, b[i]);
3379 }
3380
3381 // remove the marks of subsumed literals
3382 b = s->buffer2.data;
3383 n = s->buffer2.size;
3384 for (i=0; i<n; i++) {
3385 clear_lit_mark(s, b[i]);
3386 }
3387
3388 ivector_reset(&s->buffer2);
3389 }
3390
3391
3392
3393
3394 /*
3395 * Compute the conflict level of a conflict a:
3396 * - a must be an array of literals terminated by null_literal/end_clause
3397 * or by end_learned (i.e., by a negative number)
3398 * - if a is empty, the conflict level is set to s->base_level
3399 * otherwise conflict level = max { d_level(l) | l in the clause }
3400 *
3401 * Also set s->th_conflict_size to the number of literals in the conflict clause.
3402 * This is used by the caching heuristics.
3403 *
3404 * Note: computing conflict level is necessary for theory conflicts.
3405 * For conflicts detected by boolean propagation, the conflict_level
3406 * is the same as the current decision_level
3407 */
get_conflict_level(smt_core_t * s,literal_t * a)3408 static uint32_t get_conflict_level(smt_core_t *s, literal_t *a) {
3409 uint32_t k, q, i;
3410 literal_t l;
3411
3412 k = s->base_level;
3413 i = 0;
3414 for (;;) {
3415 l = a[i];
3416 if (l < 0) break;
3417 assert(literal_value(s, l) == VAL_FALSE);
3418 q = d_level(s, l);
3419 if (q > k) {
3420 k = q;
3421 }
3422 i ++;
3423 }
3424
3425 s->th_conflict_size = i;
3426
3427 return k;
3428 }
3429
3430
3431
3432
3433 /*
3434 * Search for first UIP and build the learned clause
3435 * d = solver state
3436 * - s->conflict stores a conflict clause (i.e., an array of literals
3437 * terminated by -1 or -2 with all literals false).
3438 *
3439 * result:
3440 * - the learned clause is stored in s->buffer as an array of literals
3441 * - s->buffer.data[0] is the implied literal
3442 */
3443
3444 #define process_literal(l) \
3445 do { \
3446 x = var_of(l); \
3447 if (is_var_unmarked(s, x)) { \
3448 set_var_mark(s, x); \
3449 increase_bvar_activity(s, x); \
3450 if (s->level[x] < conflict_level) { \
3451 ivector_push(buffer, l); \
3452 } else { \
3453 unresolved ++; \
3454 } \
3455 } \
3456 } while(0)
3457
3458
resolve_conflict(smt_core_t * s)3459 static void resolve_conflict(smt_core_t *s) {
3460 uint32_t i, j, conflict_level, unresolved;
3461 literal_t l, b;
3462 bvar_t x;
3463 literal_t *c, *stack;
3464 antecedent_t a;
3465 clause_t *cl;
3466 ivector_t *buffer;
3467
3468 assert(s->inconsistent);
3469 assert(s->theory_conflict || get_conflict_level(s, s->conflict) == s->decision_level);
3470 assert(s->base_level <= s->decision_level);
3471
3472 s->stats.conflicts ++;
3473
3474 c = s->conflict;
3475 conflict_level = s->decision_level;
3476
3477 /*
3478 * adjust conflict_level and backtrack to that level if the conflict
3479 * was reported by the theory solver.
3480 */
3481 if (s->theory_conflict) {
3482 conflict_level = get_conflict_level(s, c);
3483 assert(s->base_level <= conflict_level && conflict_level <= s->decision_level);
3484 backtrack_to_level(s, conflict_level);
3485 assert(s->decision_level == conflict_level);
3486
3487 // Cache as a clause
3488 if (s->th_cache_enabled) {
3489 try_cache_theory_conflict(s, s->th_conflict_size, c);
3490 }
3491 }
3492
3493 if (conflict_level == s->base_level) {
3494 // can't be resolved: unsat problem
3495 return;
3496 }
3497
3498 #if DEBUG
3499 check_marks(s);
3500 #endif
3501
3502
3503 /*
3504 * buffer stores the new clause (built by resolution)
3505 */
3506 buffer = &s->buffer;
3507 ivector_reset(buffer);
3508 unresolved = 0;
3509
3510 // reserve space for the implied literal
3511 ivector_push(buffer, null_literal);
3512
3513 /*
3514 * scan the conflict clause
3515 * - all literals of dl < conflict_level are added to buffer
3516 * - all literals are marked
3517 * - unresolved = number of literals in the conflict
3518 * clause whose decision level is equal to conflict_level
3519 */
3520 l = *c;
3521 while (l >= 0) {
3522 process_literal(l);
3523 c ++;
3524 l = *c;
3525 }
3526
3527 /*
3528 * If the conflict is a learned clause, increase its activity
3529 */
3530 if (l == end_learned) {
3531 increase_clause_activity(s, s->false_clause);
3532 }
3533
3534 assert(unresolved > 0);
3535
3536 /*
3537 * Scan the assignment stack from top to bottom and process the
3538 * antecedent of all marked literals:
3539 * - all the literals processed have decision_level == conflict_level
3540 * - the code works if unresolved == 1 (which may happen for theory conflicts)
3541 */
3542 stack = s->stack.lit;
3543 j = s->stack.top;
3544 for (;;) {
3545 j --;
3546 b = stack[j];
3547 assert(d_level(s, b) == conflict_level);
3548 if (is_lit_marked(s, b)) {
3549 if (unresolved == 1) {
3550 // not b is the implied literal; we're done.
3551 buffer->data[0] = not(b);
3552 break;
3553
3554 } else {
3555 unresolved --;
3556 clear_lit_mark(s, b);
3557 a = s->antecedent[var_of(b)];
3558 /*
3559 * Process b's antecedent:
3560 */
3561 switch (antecedent_tag(a)) {
3562 case clause0_tag:
3563 case clause1_tag:
3564 cl = clause_antecedent(a);
3565 i = clause_index(a);
3566 c = cl->cl;
3567 assert(c[i] == b);
3568 // process other watched literal
3569 l = c[i^1];
3570 process_literal(l);
3571 // rest of the clause
3572 c += 2;
3573 l = *c;
3574 while (l >= 0) {
3575 process_literal(l);
3576 c ++;
3577 l = *c;
3578 }
3579 if (l == end_learned) {
3580 increase_clause_activity(s, cl);
3581 }
3582 break;
3583
3584 case literal_tag:
3585 l = literal_antecedent(a);
3586 process_literal(l);
3587 break;
3588
3589 case generic_tag:
3590 explain_antecedent(s, b, a);
3591 c = s->explanation.data;
3592 // explanation is c[0] ... c[n-1] where ((and c[0] ... c[n-1]) implies b)
3593 for (i=0; i<s->explanation.size; i++) {
3594 l = not(c[i]);
3595 assert(d_level(s, l) <= conflict_level);
3596 process_literal(l);
3597 }
3598 // cache the implication as a learned clause
3599 if (s->th_cache_enabled) {
3600 assert(i == s->explanation.size);
3601 try_cache_theory_implication(s, i, c, b);
3602 }
3603 break;
3604 }
3605 }
3606 }
3607 }
3608
3609 // EXPERIMENTAL
3610 // if (s->etable != NULL) {
3611 // test_eq_conflict(s);
3612 // test_eq_clause(s, "before simplification", s-> buffer.size, s->buffer.data);
3613 // }
3614
3615
3616 /*
3617 * Simplify the learned clause and clear the marks
3618 */
3619 simplify_learned_clause(s);
3620
3621 #if DEBUG
3622 check_marks(s);
3623 #endif
3624
3625 /*
3626 * Clear the conflict flags
3627 */
3628 s->inconsistent = false;
3629 s->theory_conflict = false;
3630
3631 /*
3632 * Add the learned clause: this causes backtracking
3633 * and assert the implied literal
3634 */
3635 add_learned_clause(s, s->buffer.size, s->buffer.data);
3636 }
3637
3638
3639
3640
3641 /*********************************
3642 * ASSUMPTIONS AND UNSAT CORES *
3643 ********************************/
3644
3645 #ifndef NDEBUG
good_assumption_index(smt_core_t * s)3646 static bool good_assumption_index(smt_core_t *s) {
3647 uint32_t i;
3648 literal_t l;
3649
3650 for (i=0; i<s->assumption_index; i++) {
3651 l = s->assumptions[i];
3652 if (literal_value(s, l) != VAL_TRUE) {
3653 return false;
3654 }
3655 }
3656 return true;
3657 }
3658 #endif
3659
3660
3661 /*
3662 * Get the next assumption for the current decision_level
3663 * - s->status mut be SEARCHING
3664 * - this scans the assumption array to search for an assumption
3665 * that is not already true.
3666 * - returns an assumption l or null_literal if all assumptions
3667 * are true (or if there are no assumptions)
3668 */
get_next_assumption(smt_core_t * s)3669 literal_t get_next_assumption(smt_core_t *s) {
3670 uint32_t i, n;
3671 literal_t l;
3672
3673 assert(good_assumption_index(s));
3674
3675 n = s->num_assumptions;
3676 for (i=s->assumption_index; i<n; i++) {
3677 l = s->assumptions[i];
3678 if (literal_value(s, l) != VAL_TRUE) {
3679 s->assumption_index = i+1;
3680 return l;
3681 }
3682 }
3683
3684 s->assumption_index = n;
3685 return null_literal;
3686 }
3687
3688
3689 /*
3690 * Store l as a bad assumption:
3691 */
save_conflicting_assumption(smt_core_t * s,literal_t l)3692 void save_conflicting_assumption(smt_core_t *s, literal_t l) {
3693 assert(literal_value(s, l) == VAL_FALSE);
3694 s->bad_assumption = l;
3695 s->status = STATUS_UNSAT;
3696 }
3697
3698
3699 /*
3700 * UNSAT CORE CONSTRUCTION
3701 */
3702
3703 /*
3704 * We use a queue + a hash set to mark all antecedent literals
3705 * already seen. The following functions add literals to the
3706 * queue and set if they have not been seen before and if they
3707 * are assigned at a decision level > base_level.
3708 *
3709 * We store var_of(l) rather than l in the set. This simplifies the
3710 * processing of clause antecedents:
3711 * - if l is implied by clause c then the clause looks like (l \/ c[0] ... \/ c[n-1])
3712 * - l is the only true literal in c.
3713 * - when we visit the clause, we call visit(not(l)), visit(not(c[0])), ..., visit(not c([n-1]))
3714 * - at this point l has been visited so var_of(l) is in the set.
3715 * - since var_of(l) = var_of(not(l)) is already in the set, we don't add not(l) to the queue.
3716 */
unsat_core_visit_literal(smt_core_t * s,int_hset_t * set,int_queue_t * queue,literal_t l)3717 static void unsat_core_visit_literal(smt_core_t *s, int_hset_t *set, int_queue_t *queue, literal_t l) {
3718 bvar_t x;
3719
3720 x = var_of(l);
3721 if (s->level[x] > s->base_level && int_hset_add(set, x)) {
3722 assert(literal_value(s, l) == VAL_TRUE);
3723 int_queue_push(queue, l);
3724 }
3725 }
3726
3727 /*
3728 * cl is (l \/ c[1] \/ .... \/ c[n]) where l is the implied literal
3729 * c[1] ... c[n] are all false in the current assignment
3730 * so the antecedents of l are (not c[0]) ... (not c[n])
3731 */
unsat_core_visit_clause(smt_core_t * s,int_hset_t * set,int_queue_t * queue,clause_t * cl)3732 static void unsat_core_visit_clause(smt_core_t *s, int_hset_t *set, int_queue_t *queue, clause_t *cl) {
3733 literal_t *c;
3734 literal_t l;
3735
3736 c = cl->cl;
3737 l = *c;
3738 while (l >= 0) {
3739 unsat_core_visit_literal(s, set, queue, not(l));
3740 c ++;
3741 l = *c;
3742 }
3743 }
3744
3745 /*
3746 * explanation is a vector of n literals c[0] ... c[n-1] such that
3747 * (and c[0] ... c[n-1]) implies some other literal l.
3748 */
unsat_core_visit_explanation(smt_core_t * s,int_hset_t * set,int_queue_t * queue,ivector_t * explanation)3749 static void unsat_core_visit_explanation(smt_core_t *s, int_hset_t *set, int_queue_t *queue, ivector_t *explanation) {
3750 uint32_t i, n;
3751 literal_t l;
3752
3753 n = explanation->size;
3754 for (i=0; i<n; i++) {
3755 l = explanation->data[i];
3756 unsat_core_visit_literal(s, set, queue, l);
3757 }
3758 }
3759
3760
3761 /*
3762 * Visit the antecedents of l
3763 */
unsat_core_visit_antecedents(smt_core_t * s,int_hset_t * set,int_queue_t * queue,literal_t l)3764 static void unsat_core_visit_antecedents(smt_core_t *s, int_hset_t *set, int_queue_t *queue, literal_t l) {
3765 antecedent_t a;
3766 literal_t q;
3767
3768 a = s->antecedent[var_of(l)];
3769 switch (antecedent_tag(a)) {
3770 case clause0_tag:
3771 case clause1_tag:
3772 unsat_core_visit_clause(s, set, queue, clause_antecedent(a));
3773 break;
3774
3775 case literal_tag:
3776 q = literal_antecedent(a);
3777 if (q != null_literal) {
3778 assert(literal_value(s, q) == VAL_FALSE);
3779 unsat_core_visit_literal(s, set, queue, not(q));
3780 }
3781 break;
3782
3783 case generic_tag:
3784 // ask the theory solver for an explanation
3785 explain_antecedent(s, l, a);
3786 unsat_core_visit_explanation(s, set, queue, &s->explanation);
3787 break;
3788 }
3789 }
3790
3791
3792 /*
3793 * Visit all literals in queue and compute their antecedents.
3794 * Add any antecedent that's a decision literal to vector v.
3795 */
collect_decision_antecedents(smt_core_t * s,int_hset_t * set,int_queue_t * queue,ivector_t * v)3796 static void collect_decision_antecedents(smt_core_t *s, int_hset_t *set, int_queue_t *queue, ivector_t *v) {
3797 antecedent_t a;
3798 literal_t l;
3799
3800 while (! int_queue_is_empty(queue)) {
3801 l = int_queue_pop(queue);
3802 assert(literal_value(s, l) == VAL_TRUE &&
3803 s->level[var_of(l)] > s->base_level);
3804
3805 a = s->antecedent[var_of(l)];
3806 if (a == mk_literal_antecedent(null_literal)) {
3807 // l is a decision
3808 ivector_push(v, l);
3809 } else {
3810 unsat_core_visit_antecedents(s, set, queue, l);
3811 }
3812 }
3813 }
3814
3815
3816 /*
3817 * Compute an unsat core from the bad assumption:
3818 * - we collect all decision literals that are antecedents of the bad assumption
3819 * - if there is no bad assumption, we return an empty core
3820 */
build_unsat_core(smt_core_t * s,ivector_t * v)3821 void build_unsat_core(smt_core_t *s, ivector_t *v) {
3822 int_hset_t visited;
3823 int_queue_t queue;
3824 literal_t l;
3825
3826 assert(s->status == STATUS_UNSAT);
3827 ivector_reset(v);
3828 l = s->bad_assumption;
3829 if (l != null_literal) {
3830 init_int_queue(&queue, 0);
3831 init_int_hset(&visited, 0);
3832
3833 assert(literal_value(s, l) == VAL_FALSE);
3834
3835 // collect all decision literals that imply not l
3836 unsat_core_visit_antecedents(s, &visited, &queue, not(l));
3837 collect_decision_antecedents(s, &visited, &queue, v);
3838 // the literals in v imply (not l)
3839 // the core is (v and l)
3840 ivector_push(v, l);
3841
3842 delete_int_hset(&visited);
3843 delete_int_queue(&queue);
3844 }
3845 }
3846
3847
3848
3849
3850 /*************************************
3851 * ADDITION OF LEMMAS AND CLAUSES *
3852 ************************************/
3853
3854 /*
3855 * Before addition, clauses are simplified with respect to the
3856 * base-level assignment:
3857 * - if a clause contains a literal true at the base level,
3858 * or two complementary literals, then it's trivially true
3859 * so it is ignored.
3860 * - otherwise all literals false at the base level are removed
3861 * and duplicate literals are removed
3862 * - at this point, the clause contains no literals assigned
3863 * at the base level.
3864 *
3865 * For a clause added during the search, we examine its truth value
3866 * at the current decision level.
3867 * - the clause if true if one of its literals is true
3868 * - the clause if false if all its literals are false
3869 * - the clause is undef if it has some undef literals and all other
3870 * literals are false.
3871 * To find watched literals:
3872 * - for a false clause, take two literals of highest d_level
3873 * - for an undef clause, take two unassigned literals if that's possible,
3874 * otherwise take the unassigned literal + a false literal of highest d_level
3875 * - for a true clause, let
3876 * d = min { d_level(l) | l in clause and l is true }
3877 * then the watched literals can be any literals of d_level >= d.
3878 *
3879 * We backtrack if the clause is false or if it contains a single
3880 * unassigned literal and all other literals are false.
3881 * - the backtrack level k is computed as follows:
3882 * - for unit clauses, k = the base level
3883 * - for a clause with a single undef literal.
3884 * k = max { d_level(l) | l in clause and l is false }
3885 * - for a false clause, sort literals in decreasing d_level order
3886 * k = d_level of the second literal in this order
3887 * - after backtracking to level k: two cases are possible
3888 * 1) all literals are still false. We record the clause as a conflict.
3889 * (this may overwrite an existing conflict but that's OK. We need
3890 * to keep the conflict of lowest d_level anyway).
3891 * 2) one literal is unassigned, all other are false. We do a
3892 * unit propagation step (to make the unassigned literal true).
3893 *
3894 * If several clauses are added in succession, then one may cause a conflict
3895 * at level k0 that gets cleared later by another clause that causes backtracking
3896 * to a lower level.
3897 */
3898
3899 /*
3900 * Create a (simplified) problem clause
3901 * - a must not contain duplicate literals
3902 * - a must not be trivially true at the base level
3903 * - a[0] and a[1] must be valid watched literals
3904 * - return the new clause
3905 */
new_problem_clause(smt_core_t * s,uint32_t n,literal_t * a)3906 static clause_t *new_problem_clause(smt_core_t *s, uint32_t n, literal_t *a) {
3907 clause_t *cl;
3908 literal_t l;
3909
3910 #if TRACE
3911 uint32_t i;
3912 printf("---> DPLL: Add problem clause: {");
3913 for (i=0; i<n; i++) {
3914 printf(" ");
3915 print_literal(stdout, a[i]);
3916 }
3917 printf(" }\n");
3918 fflush(stdout);
3919 #endif
3920
3921 cl = new_clause(n, a);
3922 add_clause_to_vector(&s->problem_clauses, cl);
3923
3924 // add cl at the start of watch lists
3925 l = a[0];
3926 s->watch[l] = cons(0, cl, s->watch[l]);
3927
3928 l = a[1];
3929 s->watch[l] = cons(1, cl, s->watch[l]);
3930
3931 s->nb_prob_clauses ++;
3932 s->nb_clauses ++;
3933 s->stats.prob_literals += n;
3934
3935 return cl;
3936 }
3937
3938
3939 /*
3940 * Add unit clause { l } after simplification
3941 * - l must not be assigned at the base level
3942 */
add_simplified_unit_clause(smt_core_t * s,literal_t l)3943 static void add_simplified_unit_clause(smt_core_t *s, literal_t l) {
3944 #if TRACE
3945 printf("---> DPLL: Add unit clause: { ");
3946 print_literal(stdout, l);
3947 printf(" }\n");
3948 fflush(stdout);
3949 #endif
3950
3951 if (s->inconsistent && s->decision_level > s->base_level) {
3952 s->inconsistent = false; // clear conflict
3953 }
3954 backtrack_to_base_level(s);
3955 assign_literal(s, l);
3956 s->nb_unit_clauses ++;
3957 }
3958
3959
3960 /*
3961 * Add binary clause { l0 l1 } after simplification
3962 * - l0 and l1 must not be assigned at the base level
3963 */
add_simplified_binary_clause(smt_core_t * s,literal_t l0,literal_t l1)3964 static void add_simplified_binary_clause(smt_core_t *s, literal_t l0, literal_t l1) {
3965 uint32_t k0, k1;
3966 bval_t v0, v1;
3967
3968 direct_binary_clause(s, l0, l1); // add the clause
3969
3970 if (s->base_level == s->decision_level) {
3971 assert(literal_is_unassigned(s, l0) && literal_is_unassigned(s, l1));
3972 return;
3973 }
3974
3975 k0 = UINT32_MAX;
3976 k1 = UINT32_MAX;
3977 v0 = literal_value(s, l0);
3978 if (bval_is_def(v0)) k0 = s->level[var_of(l0)];
3979 v1 = literal_value(s, l1);
3980 if (bval_is_def(v1)) k1 = s->level[var_of(l1)];
3981
3982 if (v0 == VAL_FALSE && k0 < k1) {
3983 // l1 implied at level k0
3984 if (k0 < s->decision_level) {
3985 backtrack_to_level(s, k0);
3986 s->inconsistent = false; // clear conflict if any
3987 }
3988 implied_literal(s, l1, mk_literal_antecedent(l0));
3989
3990 } else if (v1 == VAL_FALSE && k1 < k0) {
3991 // l0 implied at level k1
3992 if (k1 < s->decision_level) {
3993 backtrack_to_level(s, k1);
3994 s->inconsistent = false; // clear conflict if any
3995 }
3996 implied_literal(s, l0, mk_literal_antecedent(l1));
3997
3998 } else if (v0 == VAL_FALSE && v1 == VAL_FALSE) {
3999 assert(k0 == k1);
4000 // conflict at level k0
4001 backtrack_to_level(s, k0);
4002 record_binary_conflict(s, l0, l1);
4003 }
4004 }
4005
4006
4007 /*
4008 * For selecting watched literals, we pick two literals
4009 * that are minimal for a preference relation <
4010 *
4011 * To compare l and l', we look at
4012 * (v k) where v = value of l and k = level of l
4013 * (v' k') where v' = value of l' and k' = level of l'
4014 *
4015 * Rules:
4016 * (true, _) < (undef, _) < (false, _)
4017 * k < k' implies (true, k) < (true, k')
4018 * k' < k implies (false, k) < (false, k')
4019 *
4020 * Other choices are possible but we must ensure
4021 * (undef, _) < (false, _)
4022 * k' < k implies (false, k) < (false, k')
4023 *
4024 * Prefer returns true if (v1, k1) < (v2, k2)
4025 */
4026
4027 /*
4028 * Priority table:
4029 * - prio[true] = 1
4030 * - prio[undef] = 0
4031 * - prio[false] = -1
4032 *
4033 * If prio[v1] > prio[v2] then v1 is preferred
4034 * If prio[v1] = prio[v2]
4035 */
4036 static const int8_t prio[4] = {
4037 0, 0, -1, +1,
4038 };
4039
prefer(bval_t v1,uint32_t k1,bval_t v2,uint32_t k2)4040 static bool prefer(bval_t v1, uint32_t k1, bval_t v2, uint32_t k2) {
4041 int8_t p1, p2;
4042 p1 = prio[v1];
4043 p2 = prio[v2];
4044 if (p1 == p2) {
4045 return (v1 == VAL_TRUE && k1 < k2) || (v1 == VAL_FALSE && k1 > k2);
4046 } else {
4047 return p1 > p2;
4048 }
4049 }
4050
4051
4052 /*
4053 * Add simplified clause { a[0] ... a[n-1] }
4054 * - a[0] ... a[n-1] are not assigned at the base level
4055 * - n >= 3
4056 */
add_simplified_clause(smt_core_t * s,uint32_t n,literal_t * a)4057 static void add_simplified_clause(smt_core_t *s, uint32_t n, literal_t *a) {
4058 uint32_t i, k0, k1, k;
4059 bval_t v0, v1, v;
4060 literal_t l;
4061 clause_t *cl;
4062
4063 assert(n >= 3);
4064
4065 if (s->base_level == s->decision_level) {
4066 new_problem_clause(s, n, a);
4067 return;
4068 }
4069
4070 // find watched literals
4071 l = a[0];
4072 v0 = literal_value(s, l);
4073 k0 = s->level[var_of(l)];
4074
4075 l = a[1];
4076 v1 = literal_value(s, l);
4077 k1 = s->level[var_of(l)];
4078 if (prefer(v1, k1, v0, k0)) {
4079 // swap a[0] and a[1]
4080 a[1] = a[0]; a[0] = l;
4081 v = v0; v0 = v1; v1 = v;
4082 k = k0; k0 = k1; k1 = k;
4083 }
4084
4085 for (i=2; i<n; i++) {
4086 l = a[i];
4087 v = literal_value(s, l);
4088 k = s->level[var_of(l)];
4089 if (prefer(v, k, v0, k0)) {
4090 // circular rotation: a[i] --> a[0] --> a[1] --> a[i]
4091 a[i] = a[1]; a[1] = a[0]; a[0] = l;
4092 v1 = v0; k1 = k0;
4093 v0 = v; k0 = k;
4094 } else if (prefer(v, k, v1, k1)) {
4095 // swap a[i] and a[1]
4096 a[i] = a[1]; a[1] = l;
4097 v1 = v; k1 = k;
4098 }
4099 }
4100
4101 #if DEBUG
4102 check_watched_literals(s, n, a);
4103 #endif
4104
4105 cl = new_problem_clause(s, n, a);
4106
4107 if (bval_is_undef(v0)) k0 = UINT32_MAX;
4108 if (bval_is_undef(v1)) k1 = UINT32_MAX;
4109
4110 if (v0 == VAL_FALSE && k0 < k1) {
4111 // a[1] implied at level k0
4112 if (k0 < s->decision_level) {
4113 backtrack_to_level(s, k0);
4114 s->inconsistent = false; // clear conflict if any
4115 }
4116 implied_literal(s, a[1], mk_clause1_antecedent(cl));
4117
4118 } else if (v1 == VAL_FALSE && k1 < k0) {
4119 // a[0] implied at level k1
4120 if (k1 < s->decision_level) {
4121 backtrack_to_level(s, k1);
4122 s->inconsistent = false; // clear conflict if any
4123 }
4124 implied_literal(s, a[0], mk_clause0_antecedent(cl));
4125
4126 } else if (v0 == VAL_FALSE && v1 == VAL_FALSE) {
4127 assert(k0 == k1);
4128 backtrack_to_level(s, k0);
4129 record_clause_conflict(s, cl);
4130 }
4131
4132 }
4133
4134
4135
4136
4137 /*
4138 * Simplify clause a[0... n-1]
4139 * - remove all literals false at base-level
4140 * - remove duplicate literals
4141 * - check whether the clause is true at base-level
4142 * Return code:
4143 * - true means the clause is not trivial
4144 * n is updated and the simplified clause is stored in a[0 .. n-1].
4145 * - false means the clause contains complementary literals or
4146 * a literal true at the base level
4147 */
preprocess_clause(smt_core_t * s,uint32_t * n,literal_t * a)4148 static bool preprocess_clause(smt_core_t *s, uint32_t *n, literal_t *a) {
4149 uint32_t i, j, m;
4150 literal_t l, l_aux;
4151
4152 m = *n;
4153 if (m == 0) return true;
4154
4155 // remove duplicates/check for complementary literals
4156 int_array_sort(a, m);
4157 l = a[0];
4158 j = 1;
4159 for (i=1; i<m; i++) {
4160 l_aux = a[i];
4161 if (l_aux != l) {
4162 if (l_aux == not(l)) return false; // true clause
4163 a[j++] = l_aux;
4164 l = l_aux;
4165 }
4166 }
4167 m = j;
4168
4169 // remove false literals/check for true literals
4170 j = 0;
4171 for (i=0; i<m; i++) {
4172 l = a[i];
4173 switch (literal_base_value(s, l)) {
4174 case VAL_FALSE:
4175 break;
4176 case VAL_UNDEF_FALSE:
4177 case VAL_UNDEF_TRUE:
4178 a[j++] = l;
4179 break;
4180 case VAL_TRUE:
4181 return false; // true clause
4182 }
4183 }
4184
4185 *n = j;
4186 return true;
4187 }
4188
4189
4190
4191
4192
4193 /*
4194 * External API to add clauses:
4195 * - can be called if s->status is IDLE or SEARCHING
4196 * - if a clause is added on the fly, when decision_level > base_level,
4197 * we copy it into the lemma queue for future processing.
4198 * The theory solver may call the clause-addition function within
4199 * its propagate or backtrack functions.
4200 */
4201
4202 /*
4203 * Check for on-the-fly addition
4204 * (if compiled in DEBUG mode also abort
4205 * if s->status is not IDLE or SEARCHING or INTERRUPTED).
4206 */
on_the_fly(smt_core_t * s)4207 static bool on_the_fly(smt_core_t *s) {
4208 assert((s->status == STATUS_IDLE && s->decision_level == s->base_level) ||
4209 (s->status == STATUS_SEARCHING && s->decision_level >= s->base_level) ||
4210 (s->status == STATUS_INTERRUPTED && s->decision_level >= s->base_level));
4211 return s->status != STATUS_IDLE;
4212 }
4213
4214 /*
4215 * Record the empty clause as a conflict
4216 * - if resolve conflict is called after this, it will do the
4217 * right thing (namely, see that the conflict can't be resolved).
4218 */
record_empty_conflict(smt_core_t * s)4219 static void record_empty_conflict(smt_core_t *s) {
4220 assert(s->decision_level == s->base_level);
4221
4222 #if TRACE
4223 printf("---> DPLL: Add empty clause: {}\n");
4224 fflush(stdout);
4225 #endif
4226 s->inconsistent = true;
4227 s->conflict_buffer[0] = end_clause;
4228 s->conflict = s->conflict_buffer;
4229 }
4230
4231
4232 /*
4233 * Add the empty clause (we provide this for completeness)
4234 */
add_empty_clause(smt_core_t * s)4235 void add_empty_clause(smt_core_t *s) {
4236 if (on_the_fly(s)) {
4237 push_lemma(&s->lemmas, 0, NULL);
4238 return;
4239 }
4240 record_empty_conflict(s);
4241 }
4242
4243
4244 /*
4245 * Add a unit clause
4246 */
add_unit_clause(smt_core_t * s,literal_t l)4247 void add_unit_clause(smt_core_t *s, literal_t l) {
4248 if (on_the_fly(s) && s->decision_level > s->base_level) {
4249 #if DEBUG
4250 check_lemma(s, 1, &l);
4251 #endif
4252 push_lemma(&s->lemmas, 1, &l);
4253 return;
4254 }
4255
4256 #if TRACE
4257 printf("---> DPLL: Add unit clause: { ");
4258 print_literal(stdout, l);
4259 printf(" }\n");
4260 fflush(stdout);
4261 #endif
4262
4263 assert(0 <= l && l < s->nlits);
4264
4265 if (literal_value(s, l) == VAL_TRUE && s->level[var_of(l)] <= s->base_level) {
4266 return; // l is already true at the base level
4267 }
4268
4269 if (literal_value(s, l) == VAL_FALSE) {
4270 // conflict (the whole thing is unsat)
4271 s->inconsistent = true;
4272 s->conflict = s->conflict_buffer;
4273 s->conflict_buffer[0] = l;
4274 s->conflict_buffer[1] = end_clause;
4275
4276 } else {
4277 assign_literal(s, l);
4278 s->nb_unit_clauses ++;
4279 }
4280 }
4281
4282
4283 /*
4284 * Simplify then add clause a[0 ... n-1]
4285 * - this modifies array a
4286 */
add_clause_unsafe(smt_core_t * s,uint32_t n,literal_t * a)4287 void add_clause_unsafe(smt_core_t *s, uint32_t n, literal_t *a) {
4288 if (on_the_fly(s)) {
4289 #if DEBUG
4290 check_lemma(s, n, a);
4291 #endif
4292 push_lemma(&s->lemmas, n, a);
4293 return;
4294 }
4295
4296 if (preprocess_clause(s, &n, a)) {
4297 if (n > 2) {
4298 // add_simplified_clause(s, n, a);
4299 new_problem_clause(s, n, a);
4300 } else if (n == 2) {
4301 // add_simplified_binary_clause(s, a[0], a[1]);
4302 direct_binary_clause(s, a[0], a[1]);
4303 } else if (n == 1) {
4304 add_simplified_unit_clause(s, a[0]);
4305 } else {
4306 record_empty_conflict(s);
4307 }
4308 }
4309 #if TRACE
4310 else {
4311 printf("---> DPLL: Skipped true clause\n");
4312 fflush(stdout);
4313 }
4314 #endif
4315 }
4316
4317 /*
4318 * Simplify then add clause a[0 ... n-1]
4319 * - makes a copy of a so it's safe to use
4320 */
add_clause(smt_core_t * s,uint32_t n,literal_t * a)4321 void add_clause(smt_core_t *s, uint32_t n, literal_t *a) {
4322 ivector_t *v;
4323
4324 if (on_the_fly(s)) {
4325 #if DEBUG
4326 check_lemma(s, n, a);
4327 #endif
4328 push_lemma(&s->lemmas, n, a);
4329 return;
4330 }
4331
4332 // use s->buffer2 as an auxiliary buffer to make a copy of a[0 .. n-1]
4333 v = &s->buffer2;
4334 assert(v->size == 0);
4335 ivector_copy(v, a, n);
4336 assert(v->size == n);
4337
4338 // use the copy here
4339 a = v->data;
4340 if (preprocess_clause(s, &n, a)) {
4341 if (n > 2) {
4342 // add_simplified_clause(s, n, a);
4343 new_problem_clause(s, n, a);
4344 } else if (n == 2) {
4345 // add_simplified_binary_clause(s, a[0], a[1]);
4346 direct_binary_clause(s, a[0], a[1]);
4347 } else if (n == 1) {
4348 add_simplified_unit_clause(s, a[0]);
4349 } else {
4350 record_empty_conflict(s);
4351 }
4352 }
4353 #if TRACE
4354 else {
4355 printf("---> DPLL: Skipped true clause\n");
4356 fflush(stdout);
4357 }
4358 #endif
4359
4360 ivector_reset(v);
4361 }
4362
4363
4364 /*
4365 * Short cuts
4366 */
add_binary_clause(smt_core_t * s,literal_t l1,literal_t l2)4367 void add_binary_clause(smt_core_t *s, literal_t l1, literal_t l2) {
4368 literal_t a[2];
4369
4370 a[0] = l1;
4371 a[1] = l2;
4372 add_clause_unsafe(s, 2, a);
4373 }
4374
add_ternary_clause(smt_core_t * s,literal_t l1,literal_t l2,literal_t l3)4375 void add_ternary_clause(smt_core_t *s, literal_t l1, literal_t l2, literal_t l3) {
4376 literal_t a[3];
4377
4378 a[0] = l1;
4379 a[1] = l2;
4380 a[2] = l3;
4381 add_clause_unsafe(s, 3, a);
4382 }
4383
4384
4385
4386
4387
4388 /********************************
4389 * DEAL WITH THE LEMMA QUEUE *
4390 *******************************/
4391
4392 /*
4393 * Find the length of a lemma a:
4394 * - a must be terminated by null_literal (or any negative end marker)
4395 */
lemma_length(literal_t * a)4396 static uint32_t lemma_length(literal_t *a) {
4397 uint32_t n;
4398
4399 n = 0;
4400 while (*a >= 0) {
4401 a ++;
4402 n ++;
4403 }
4404 return n;
4405 }
4406
4407
4408 /*
4409 * Add lemma: similar to add_clause but does more work
4410 * - n = length of the lemma
4411 * - a = array of literals (lemma is a[0] ... a[n-1])
4412 */
add_lemma(smt_core_t * s,uint32_t n,literal_t * a)4413 static void add_lemma(smt_core_t *s, uint32_t n, literal_t *a) {
4414 if (preprocess_clause(s, &n, a)) {
4415 if (n > 2) {
4416 add_simplified_clause(s, n, a);
4417 } else if (n == 2) {
4418 add_simplified_binary_clause(s, a[0], a[1]);
4419 } else if (n == 1) {
4420 add_simplified_unit_clause(s, a[0]);
4421 } else {
4422 backtrack_to_base_level(s);
4423 record_empty_conflict(s);
4424 }
4425 }
4426 #if TRACE
4427 else {
4428 printf("---> DPLL: Skipped true lemma\n");
4429 fflush(stdout);
4430 }
4431 #endif
4432
4433 }
4434
4435
4436 /*
4437 * Add all queued lemmas to the database.
4438 * - this may cause backtracking
4439 * - a conflict clause may be recorded
4440 * If so, conflict resolution must be called outside this function
4441 */
add_all_lemmas(smt_core_t * s)4442 static void add_all_lemmas(smt_core_t *s) {
4443 lemma_block_t *tmp;
4444 literal_t *lemma;
4445 uint32_t i, j, n;
4446
4447 for (i=0; i<s->lemmas.free_block; i++) {
4448 tmp = s->lemmas.block[i];
4449 lemma = tmp->data;
4450 j = 0;
4451 while (j < tmp->ptr) {
4452 /*
4453 * it's possible for new lemmas to be added within this loop
4454 * because clause addition may cause backtracking and
4455 * the theory solver is allowed to create lemmas within backtrack.
4456 */
4457 n = lemma_length(lemma);
4458 add_lemma(s, n, lemma);
4459 n ++; // skip the end marker
4460 j += n;
4461 lemma += n;
4462 }
4463 }
4464
4465 // Empty the queue now:
4466 reset_lemma_queue(&s->lemmas);
4467 }
4468
4469
4470
4471
4472
4473 /*********************************
4474 * DELETION OF LEARNED CLAUSES *
4475 ********************************/
4476
4477 /*
4478 * Reorder an array a[low ... high-1] of learned clauses so that
4479 * the clauses are divided in two half arrays:
4480 * - the clauses of highest activities are all stored in a[low...half - 1]
4481 * - the clauses of lowest activities are in a[half ... high-1],
4482 * where half = (low + high) / 2.
4483 */
quick_split(clause_t ** a,uint32_t low,uint32_t high)4484 static void quick_split(clause_t **a, uint32_t low, uint32_t high) {
4485 uint32_t i, j, half;
4486 float pivot;
4487 clause_t *aux;
4488
4489 if (high <= low + 1) return;
4490
4491 half = (low + high)/2;
4492
4493 do {
4494 i = low;
4495 j = high;
4496 pivot = get_activity(a[i]);
4497
4498 do { j --; } while (get_activity(a[j]) < pivot);
4499 do { i ++; } while (i <= j && get_activity(a[i]) > pivot);
4500
4501 while (i < j) {
4502 // a[i].act <= pivot and a[j].act >= pivot: swap a[i] and a[j]
4503 aux = a[i];
4504 a[i] = a[j];
4505 a[j] = aux;
4506
4507 do { j--; } while (get_activity(a[j]) < pivot);
4508 do { i++; } while (get_activity(a[i]) > pivot);
4509 }
4510
4511 // a[j].act >= pivot, a[low].act = pivot: swap a[low] and a[i]
4512 aux = a[low];
4513 a[low] = a[j];
4514 a[j] = aux;
4515
4516 /*
4517 * at this point:
4518 * - all clauses in a[low,.., j - 1] have activity >= pivot
4519 * - activity of a[j] == pivot
4520 * - all clauses in a[j+1,..., high-1] have activity <= pivot
4521 * reapply the procedure to whichever of the two subarrays
4522 * contains the half point
4523 */
4524 if (j < half) {
4525 low = j + 1;
4526 } else {
4527 high = j;
4528 }
4529 } while (j != half);
4530 }
4531
4532
4533 /*
4534 * Apply this to a vector v of learned_clauses
4535 */
reorder_clause_vector(clause_t ** v)4536 static void reorder_clause_vector(clause_t **v) {
4537 quick_split(v, 0, get_cv_size(v));
4538 }
4539
4540
4541 /*
4542 * Auxiliary function: follow clause list of l0
4543 * Remove all clauses marked for removal
4544 */
cleanup_watch_list(smt_core_t * s,literal_t l0)4545 static void cleanup_watch_list(smt_core_t *s, literal_t l0) {
4546 link_t lnk;
4547 clause_t *cl;
4548 link_t *list;
4549
4550 list = s->watch + l0;
4551 for (lnk = *list; lnk != NULL_LINK; lnk = next_of(lnk)) {
4552 cl = clause_of(lnk);
4553 if (! is_clause_to_be_removed(cl)) {
4554 *list = lnk;
4555 list = cdr_ptr(lnk);
4556 }
4557 }
4558
4559 *list = NULL_LINK; // end of list
4560 }
4561
4562
4563 /*
4564 * Update all watch lists: remove all clauses marked for deletion.
4565 */
cleanup_watch_lists(smt_core_t * s)4566 static void cleanup_watch_lists(smt_core_t *s) {
4567 uint32_t i, n;
4568
4569 n = s->nlits;
4570 for (i=0; i<n; i ++) {
4571 cleanup_watch_list(s, i);
4572 }
4573 }
4574
4575
4576 /*
4577 * Check whether cl is an antecedent clause
4578 */
clause_is_locked(smt_core_t * s,clause_t * cl)4579 static bool clause_is_locked(smt_core_t *s, clause_t *cl) {
4580 bvar_t x0, x1;
4581
4582 x0 = var_of(get_first_watch(cl));
4583 x1 = var_of(get_second_watch(cl));
4584
4585 return (bval_is_def(s->value[x0]) && s->antecedent[x0] == mk_clause0_antecedent(cl))
4586 || (bval_is_def(s->value[x1]) && s->antecedent[x1] == mk_clause1_antecedent(cl));
4587 }
4588
4589
4590 /*
4591 * Delete all clauses that are marked for deletion
4592 */
delete_learned_clauses(smt_core_t * s)4593 static void delete_learned_clauses(smt_core_t *s) {
4594 uint32_t i, j, n;
4595 clause_t **v;
4596
4597 v = s->learned_clauses;
4598 n = get_cv_size(v);
4599
4600 // clean up all the watch-literal lists
4601 cleanup_watch_lists(s);
4602
4603 // do the real deletion
4604 s->stats.learned_literals = 0;
4605
4606 j = 0;
4607 for (i = 0; i<n; i++) {
4608 if (is_clause_to_be_removed(v[i])) {
4609 delete_learned_clause(v[i]);
4610 } else {
4611 s->stats.learned_literals += clause_length(v[i]);
4612 v[j] = v[i];
4613 j ++;
4614 }
4615 }
4616
4617 // set new size of the learned clause vector
4618 set_cv_size(s->learned_clauses, j);
4619 s->nb_clauses -= (n - j);
4620
4621 s->stats.learned_clauses_deleted += (n - j);
4622 }
4623
4624
4625 /*
4626 * Delete half the learned clauses, minus the locked ones (Minisat style).
4627 * This is expensive: the function scans and reconstructs the
4628 * watched lists.
4629 */
reduce_clause_database(smt_core_t * s)4630 void reduce_clause_database(smt_core_t *s) {
4631 uint32_t i, n;
4632 clause_t **v;
4633 float act_threshold;
4634
4635 v = s->learned_clauses;
4636 n = get_cv_size(v);
4637 if (n == 0) return;
4638
4639 // put the clauses with lowest activity in the upper
4640 // half of the learned clause vector.
4641 reorder_clause_vector(v);
4642
4643 act_threshold = s->cla_inc/n;
4644
4645 // prepare for deletion: all non-locked clauses, with activity less
4646 // than activity_threshold are marked for deletion.
4647 for (i=0; i<n/2; i++) {
4648 if (get_activity(v[i]) <= act_threshold && ! clause_is_locked(s, v[i])) {
4649 mark_for_removal(v[i]);
4650 }
4651 }
4652 for (i = n/2; i<n; i++) {
4653 if (! clause_is_locked(s, v[i])) {
4654 mark_for_removal(v[i]);
4655 }
4656 }
4657
4658 delete_learned_clauses(s);
4659 s->stats.reduce_calls ++;
4660 }
4661
4662
4663
4664
4665
4666 /*******************************************************
4667 * ZCHAFF-STYLE CLAUSE DELETION (AS IN YICES 1.0.XX) *
4668 ******************************************************/
4669
4670 /*
4671 * Number of unassigned literals in clause cl
4672 */
unassigned_literals(smt_core_t * s,clause_t * cl)4673 static uint32_t unassigned_literals(smt_core_t *s, clause_t *cl) {
4674 uint32_t n;
4675 literal_t l, *a;
4676
4677 n = 0;
4678 a = cl->cl;
4679 l = *a;
4680 while (l >= 0) {
4681 if (literal_is_unassigned(s,l)) n ++;
4682 a ++;
4683 l = *a;
4684 }
4685
4686 return n;
4687 }
4688
4689
4690 /*
4691 * Delete irrelevant clauses (Zchaff-style)
4692 * - split the set of learned clauses into two parts: old-clauses and young-clauses
4693 * - if there are n learned clauses in total, then the n/young_ratio most recent are young,
4694 * the rest are old. (young_ratio is 16)
4695 */
remove_irrelevant_learned_clauses(smt_core_t * s)4696 void remove_irrelevant_learned_clauses(smt_core_t *s) {
4697 clause_t **v;
4698 clause_t *cl;
4699 uint32_t i, n, p, relevance;
4700 float coeff;
4701
4702 v = s->learned_clauses;
4703 n = get_cv_size(v);
4704 if (n == 0) return;
4705
4706 p = n - n/TAIL_RATIO;
4707 coeff = (float) (HEAD_ACTIVITY - TAIL_ACTIVITY)/n;
4708
4709 for (i=0; i<n; i++) {
4710 cl = v[i];
4711 if (! clause_is_locked(s, cl)) {
4712 relevance = i < p ? HEAD_RELEVANCE : TAIL_RELEVANCE;
4713 if (get_activity(cl) < HEAD_ACTIVITY - coeff * i &&
4714 unassigned_literals(s, cl) > relevance) {
4715 mark_for_removal(cl);
4716 }
4717 }
4718 }
4719
4720 delete_learned_clauses(s);
4721 s->stats.remove_calls ++;
4722 }
4723
4724
4725
4726
4727
4728
4729 /***********************************************************
4730 * SIMPLIFICATION: REMOVE CLAUSES TRUE AT THE BASE LEVEL *
4731 **********************************************************/
4732
4733 /*
4734 * Variant of literal_value: l can be negative
4735 */
unsafe_literal_value(smt_core_t * s,literal_t l)4736 static inline bval_t unsafe_literal_value(smt_core_t *s, literal_t l) {
4737 assert(end_learned <= l && l <= (int32_t) s->nlits);
4738 return lit_val(s->value, l);
4739 }
4740
4741
4742 /*
4743 * Variant of literal_is_unassigned (same reason)
4744 */
unsafe_literal_is_unassigned(smt_core_t * s,literal_t l)4745 static inline bval_t unsafe_literal_is_unassigned(smt_core_t *s, literal_t l) {
4746 assert(end_learned <= l && l <= (int32_t) s->nlits);
4747 return bval_is_undef(s->value[var_of(l)]);
4748 }
4749
4750
4751 /*
4752 * Simplify clause cl, given the current literal assignment
4753 * - mark cl for deletion if it's true
4754 * - otherwise remove the false literals
4755 * The watched literals are unchanged.
4756 *
4757 * Update the counters aux_clauses and aux_literals if the clause
4758 * is not marked for removal.
4759 *
4760 * This is sound only at level 0.
4761 */
simplify_clause(smt_core_t * s,clause_t * cl)4762 static void simplify_clause(smt_core_t *s, clause_t *cl) {
4763 uint32_t i, j;
4764 literal_t l;
4765
4766 assert(s->base_level == 0 && s->decision_level ==0);
4767
4768 i = 0;
4769 j = 0;
4770 do {
4771 l = cl->cl[i];
4772 i ++;
4773 switch (unsafe_literal_value(s, l)) {
4774 case VAL_FALSE:
4775 break;
4776
4777 case VAL_UNDEF_FALSE:
4778 case VAL_UNDEF_TRUE:
4779 cl->cl[j] = l;
4780 j ++;
4781 break;
4782
4783 case VAL_TRUE:
4784 mark_for_removal(cl);
4785 return;
4786 }
4787 } while (l >= 0);
4788
4789 s->aux_literals += j - 1;
4790 s->aux_clauses ++;
4791 // could migrate cl to two-literal if j is 3??
4792 }
4793
4794
4795 /*
4796 * Check whether cl is true at the base level. If so mark it
4797 * for removal.
4798 */
mark_true_clause(smt_core_t * s,clause_t * cl)4799 static void mark_true_clause(smt_core_t *s, clause_t *cl) {
4800 uint32_t i;
4801 literal_t l;
4802
4803 assert(s->base_level == s->decision_level);
4804
4805 i = 0;
4806 do {
4807 l = cl->cl[i];
4808 i ++;
4809 if (unsafe_literal_value(s, l) == VAL_TRUE) {
4810 mark_for_removal(cl);
4811 return;
4812 }
4813 } while (l >= 0);
4814
4815 s->aux_literals += (i - 1);
4816 s->aux_clauses ++;
4817 }
4818
4819
4820 /*
4821 * Simplify the set of clauses given the current assignment:
4822 * - remove all clauses that are true (from the watched literals)
4823 * - remove false literals from learned clauses
4824 */
simplify_clause_set(smt_core_t * s)4825 static void simplify_clause_set(smt_core_t *s) {
4826 uint32_t i, j, n;
4827 clause_t **v;
4828
4829 assert(s->decision_level == s->base_level);
4830
4831 if (s->base_level == 0) {
4832 /*
4833 * Apply thorough simplifications at level 0
4834 */
4835 // simplify problem clauses
4836 s->aux_literals = 0;
4837 s->aux_clauses = 0;
4838 v = s->problem_clauses;
4839 n = get_cv_size(v);
4840 for (i=0; i<n; i++) {
4841 if (! is_clause_to_be_removed(v[i]) &&
4842 ! clause_is_locked(s, v[i])) {
4843 simplify_clause(s, v[i]);
4844 }
4845 }
4846 s->stats.prob_literals = s->aux_literals;
4847 s->nb_prob_clauses = s->aux_clauses;
4848
4849 // simplify learned clauses
4850 s->aux_literals = 0;
4851 s->aux_clauses = 0;
4852 v = s->learned_clauses;
4853 n = get_cv_size(v);
4854 for (i=0; i<n; i++) {
4855 assert(! is_clause_to_be_removed(v[i]));
4856 if (! clause_is_locked(s, v[i])) {
4857 simplify_clause(s, v[i]);
4858 }
4859 }
4860 s->stats.learned_literals = s->aux_literals;
4861
4862 } else {
4863 /*
4864 * Mark the true clauses for removal
4865 */
4866 // mark the true problem clauses
4867 s->aux_literals = 0;
4868 s->aux_clauses = 0;
4869 v = s->problem_clauses;
4870 n = get_cv_size(v);
4871 for (i=0; i<n; i++) {
4872 if (! is_clause_to_be_removed(v[i]) &&
4873 ! clause_is_locked(s, v[i])) {
4874 mark_true_clause(s, v[i]);
4875 }
4876 }
4877 s->stats.prob_literals = s->aux_literals;
4878 s->nb_prob_clauses = s->aux_clauses;
4879
4880 // mark the true learned clauses
4881 s->aux_literals = 0;
4882 v = s->learned_clauses;
4883 n = get_cv_size(v);
4884 for (i=0; i<n; i++) {
4885 assert(! is_clause_to_be_removed(v[i]));
4886 if (! clause_is_locked(s, v[i])) {
4887 mark_true_clause(s, v[i]);
4888 }
4889 }
4890 s->stats.learned_literals = s->aux_literals;
4891
4892 }
4893
4894 /*
4895 * cleanup the watched literal lists: all marked (i.e., true)
4896 * clauses are removed from the lists.
4897 */
4898 cleanup_watch_lists(s);
4899
4900 /*
4901 * Remove the true simplified problem clauses for good
4902 * if we're at base_level 0
4903 */
4904 if (s->base_level == 0) {
4905 v = s->problem_clauses;
4906 n = get_cv_size(v);
4907 j = 0;
4908 for (i=0; i<n; i++) {
4909 if (is_clause_to_be_removed(v[i])) {
4910 delete_clause(v[i]);
4911 } else {
4912 v[j] = v[i];
4913 j ++;
4914 }
4915 }
4916 set_cv_size(v, j);
4917 s->nb_clauses -= n - j;
4918 s->stats.prob_clauses_deleted += n - j;
4919 }
4920
4921
4922 /*
4923 * Remove the marked (i.e. true) learned clauses for good
4924 */
4925 v = s->learned_clauses;
4926 n = get_cv_size(v);
4927 j = 0;
4928 for (i=0; i<n; i++) {
4929 if (is_clause_to_be_removed(v[i])) {
4930 delete_learned_clause(v[i]);
4931 } else {
4932 v[j] = v[i];
4933 j ++;
4934 }
4935 }
4936 set_cv_size(v, j);
4937 s->nb_clauses -= n - j;
4938 s->stats.learned_clauses_deleted += n - j;
4939 }
4940
4941
4942 /*
4943 * Clean up a binary-clause vector v
4944 * - assumes that v is non-null
4945 * - remove all literals of v that are assigned at the base level
4946 * - for each deleted literal, increment sol->stats.aux_literals.
4947 * This is sound only at level 0.
4948 */
cleanup_binary_clause_vector(smt_core_t * s,literal_t * v)4949 static void cleanup_binary_clause_vector(smt_core_t *s, literal_t *v) {
4950 uint32_t i, j;
4951 literal_t l;
4952
4953 i = 0;
4954 j = 0;
4955 do {
4956 l = v[i++];
4957 if (unsafe_literal_is_unassigned(s, l)) { //keep l
4958 v[j ++] = l;
4959 }
4960 } while (l >= 0); // end-marker is copied too
4961
4962 s->aux_literals += i - j;
4963 set_lv_size(v, j - 1);
4964 }
4965
4966
4967 /*
4968 * Simplify all binary vectors affected by the current assignment
4969 * - scan the literals in the stack from sol->simplify_bottom to sol->stack.top
4970 * - remove all the binary clauses that contain one such literal
4971 * - free the binary watch vectors
4972 *
4973 * Should not be used at base_level > 0, otherwise pop won't restore the
4974 * binary clauses properly.
4975 */
simplify_binary_vectors(smt_core_t * s)4976 static void simplify_binary_vectors(smt_core_t *s) {
4977 uint32_t i, j, n;
4978 literal_t l0, *v0, l1;
4979
4980 assert(s->decision_level == 0 && s->base_level == 0);
4981
4982 s->aux_literals = 0; // counts the number of literals removed
4983 for (i = s->simplify_bottom; i < s->stack.top; i++) {
4984 l0 = s->stack.lit[i];
4985
4986 // remove all binary clauses that contain l0
4987 v0 = s->bin[l0];
4988 if (v0 != NULL) {
4989 n = get_lv_size(v0);
4990 for (j=0; j<n; j++) {
4991 l1 = v0[j];
4992 if (literal_is_unassigned(s, l1)) {
4993 // sol->bin[l1] is non null.
4994 assert(s->bin[l1] != NULL);
4995 cleanup_binary_clause_vector(s, s->bin[l1]);
4996 }
4997 }
4998
4999 delete_literal_vector(v0);
5000 s->bin[l0] = NULL;
5001 s->aux_literals += n;
5002 }
5003
5004 // remove all binary clauses that contain not(l0)
5005 l0 = not(l0);
5006 v0 = s->bin[l0];
5007 if (v0 != NULL) {
5008 s->aux_literals += get_lv_size(v0);
5009 delete_literal_vector(v0);
5010 s->bin[l0] = NULL;
5011 }
5012 }
5013
5014 s->aux_literals /= 2;
5015 s->stats.bin_clauses_deleted += s->aux_literals;
5016 s->nb_bin_clauses -= s->aux_literals;
5017
5018 s->aux_literals = 0;
5019 }
5020
5021
5022 /*
5023 * Simplify the database: problem clauses and learned clauses
5024 * - remove clauses that are true at the base level from the watched lists
5025 * - if base_level is 0, also remove binary clauses that are true at the
5026 * base level.
5027 */
simplify_clause_database(smt_core_t * s)5028 static void simplify_clause_database(smt_core_t *s) {
5029 assert(s->stack.top == s->stack.prop_ptr && s->decision_level == s->base_level);
5030
5031 simplify_clause_set(s);
5032 if (s->base_level == 0) {
5033 simplify_binary_vectors(s);
5034 }
5035
5036 s->stats.simplify_calls ++;
5037
5038 /*
5039 * The next call to simplify_clause_database is enabled when
5040 * s->decision_level == base_level &&
5041 * s->stack.top > s->simplify_bottom &&
5042 * s->stats.propagations > s->simplify_props + s->simplify_threshold
5043 *
5044 * s->simplify_threshold is set to the total number of literals.
5045 *
5046 * This is an arbitrary choice that avoids calling simplify too often.
5047 * This is copied from Minisat.
5048 */
5049 s->simplify_bottom = s->stack.top;
5050 s->simplify_props = s->stats.propagations;
5051 s->simplify_threshold = s->stats.learned_literals + s->stats.prob_literals +
5052 2 * s->nb_bin_clauses;
5053 }
5054
5055
5056
5057
5058 /**************
5059 * PUSH/POP *
5060 *************/
5061
5062 /*
5063 * Push:
5064 * - clear current assignment and reset status to IDLE if necessary
5065 * - save current base-level state
5066 * - notify the theory solver
5067 * - increase base level
5068 */
smt_push(smt_core_t * s)5069 void smt_push(smt_core_t *s) {
5070 uint32_t k;
5071
5072 /*
5073 * Abort if push_pop is not enabled
5074 */
5075 assert((s->option_flag & PUSH_POP_MASK) != 0);
5076
5077 /*
5078 * Reset assignment and status
5079 */
5080 if (s->status == STATUS_UNKNOWN || s->status == STATUS_SAT) {
5081 smt_clear(s);
5082 }
5083
5084 assert(s->status == STATUS_IDLE && s->decision_level == s->base_level);
5085
5086 /*
5087 * Save current state:
5088 * - number of variables
5089 * - number of unit clauses
5090 * - number of binary clauses
5091 * - number of problem clauses
5092 * - propagation pointers
5093 */
5094 trail_stack_save(&s->trail_stack,
5095 s->nvars, s->nb_unit_clauses, s->binary_clauses.size,
5096 get_cv_size(s->problem_clauses),
5097 s->stack.prop_ptr, s->stack.theory_ptr);
5098
5099 /*
5100 * Gate table
5101 */
5102 gate_table_push(&s->gates);
5103
5104 /*
5105 * Notify the theory solver
5106 */
5107 s->th_ctrl.push(s->th_solver);
5108
5109 /*
5110 * Increase the base_level (and decision_level)
5111 */
5112 k = s->base_level + 1;
5113 s->base_level = k;
5114 s->decision_level = k;
5115 if (s->stack.nlevels <= k) {
5116 increase_stack_levels(&s->stack);
5117 }
5118 s->stack.level_index[k] = s->stack.top;
5119
5120 }
5121
5122
5123 /*
5124 * Mark all learned clauses for removal
5125 */
remove_all_learned_clauses(smt_core_t * s)5126 static void remove_all_learned_clauses(smt_core_t *s) {
5127 uint32_t i, n;
5128 clause_t **v;
5129
5130 v = s->learned_clauses;
5131 n = get_cv_size(v);
5132
5133 for (i=0; i<n; i++) {
5134 mark_for_removal(v[i]);
5135 }
5136 }
5137
5138
5139 /*
5140 * Mark problem clauses (at indices n, n+1, ...)
5141 */
remove_problem_clauses(smt_core_t * s,uint32_t n)5142 static void remove_problem_clauses(smt_core_t *s, uint32_t n) {
5143 uint32_t m;
5144 clause_t **v;
5145 clause_t *cl;
5146
5147 v = s->problem_clauses;
5148 m = get_cv_size(v);
5149 while (n < m) {
5150 cl = v[n];
5151 if (! is_clause_to_be_removed(cl)) {
5152 mark_for_removal(cl);
5153 }
5154 n ++;
5155 }
5156 }
5157
5158
5159 /*
5160 * Reset the watch lists (to empty lists)
5161 */
reset_watch_lists(smt_core_t * s)5162 static void reset_watch_lists(smt_core_t *s) {
5163 uint32_t i, n;
5164
5165 n = s->nlits;
5166 for (i=0; i<n; i++) {
5167 s->watch[i] = NULL_LINK;
5168 }
5169 }
5170
5171
5172 /*
5173 * Restore all non-binary/non-unit clauses (to previous base-level)
5174 * Also restore stats.prob_literals
5175 * - n = number of problem clauses at the start of the current base level
5176 */
restore_clauses(smt_core_t * s,uint32_t n)5177 static void restore_clauses(smt_core_t *s, uint32_t n) {
5178 uint32_t i, m, nlits;
5179 clause_t **v;
5180 clause_t *cl;
5181 literal_t l;
5182
5183 // mark clauses for removal
5184 remove_all_learned_clauses(s);
5185 remove_problem_clauses(s, n);
5186
5187 // empty the watch lists
5188 reset_watch_lists(s);
5189
5190 // do the real deletion
5191 v = s->learned_clauses;
5192 m = get_cv_size(v);
5193 for (i=0; i<m; i++) {
5194 delete_learned_clause(v[i]);
5195 }
5196 reset_clause_vector(v);
5197
5198 v = s->problem_clauses;
5199 m = get_cv_size(v);
5200 for (i=n; i<m; i++) {
5201 delete_clause(v[i]);
5202 }
5203 set_cv_size(v, n);
5204
5205 /*
5206 * put all problem clauses back into the watch lists
5207 * and restore the marked problem clauses in v[0 ... n-1]
5208 */
5209 nlits = 0; // to count the total number of literals
5210 for (i=0; i<n; i++) {
5211 cl = v[i];
5212 if (is_clause_to_be_removed(cl)) {
5213 restore_removed_clause(cl);
5214 assert(cl->cl[0] >= 0 && cl->cl[1] >= 0);
5215 }
5216 nlits += clause_length(cl);
5217
5218 // add cl at the start of its watch lists
5219 l = cl->cl[0];
5220 s->watch[l] = cons(0, cl, s->watch[l]);
5221
5222 l = cl->cl[1];
5223 s->watch[l] = cons(1, cl, s->watch[l]);
5224 }
5225
5226
5227 s->nb_clauses = n;
5228 s->nb_prob_clauses = n;
5229 s->stats.prob_literals = nlits;
5230 s->stats.learned_literals = 0;
5231 }
5232
5233
5234 /*
5235 * Keep binary clauses in binary_clauses[0... n-1]
5236 * Remove the ones in binary_clauses[n ... ]
5237 */
restore_binary_clauses(smt_core_t * s,uint32_t n)5238 static void restore_binary_clauses(smt_core_t *s, uint32_t n) {
5239 uint32_t i;
5240 literal_t l0, l1;
5241 literal_t *bin_clauses;
5242
5243 bin_clauses = s->binary_clauses.data;
5244 i = s->binary_clauses.size;
5245 assert((i & 1) == 0 && (n & 1) == 0 && i >= n);
5246
5247 // number of clauses removed = (i - n)/2
5248 s->nb_bin_clauses -= (i - n)/2;
5249
5250 while (i > n) {
5251 i --;
5252 l0 = bin_clauses[i];
5253 i --;
5254 l1 = bin_clauses[i];
5255 // last clause added = { l1, l0 }
5256 assert(last_lv_elem(s->bin[l0]) == l1 && last_lv_elem(s->bin[l1]) == l0);
5257 literal_vector_pop(s->bin[l0]);
5258 literal_vector_pop(s->bin[l1]);
5259 }
5260
5261 ivector_shrink(&s->binary_clauses, n);
5262 }
5263
5264
5265 /*
5266 * Keep variables 0 ... n-1. Remove the rest
5267 * Must be called after restore_clauses.
5268 *
5269 * Atoms are removed if needed, but we don't call
5270 * s->th_smt.delete_atom, since s->th_ctrl.pop has been
5271 * called before this.
5272 */
restore_variables(smt_core_t * s,uint32_t n)5273 static void restore_variables(smt_core_t *s, uint32_t n) {
5274 uint32_t i, nv;
5275 literal_t l0, l1;
5276
5277 nv = s->nvars;
5278 for (i=n; i<nv; i++) {
5279 heap_remove(&s->heap, i);
5280 if (bvar_has_atom(s, i)) {
5281 remove_atom(&s->atoms, i);
5282 }
5283
5284 l0 = pos_lit(i);
5285 l1 = neg_lit(i);
5286 delete_literal_vector(s->bin[l0]);
5287 delete_literal_vector(s->bin[l1]);
5288 s->bin[l0] = NULL;
5289 s->bin[l1] = NULL;
5290 s->watch[l0] = NULL_LINK;
5291 s->watch[l1] = NULL_LINK;
5292 }
5293
5294 s->nvars = n;
5295 s->nlits = 2 * n;
5296 }
5297
5298
5299 /*
5300 * Remove the mark of all variables assigned at the current base_level
5301 */
clear_base_level_marks(smt_core_t * s)5302 static void clear_base_level_marks(smt_core_t *s) {
5303 uint32_t i, k, n;
5304 literal_t *u, l;
5305 bvar_t x;
5306
5307 u = s->stack.lit;
5308 k = s->base_level;
5309 n = s->stack.top;
5310 for (i=s->stack.level_index[k]; i<n; i++) {
5311 l = u[i];
5312 x = var_of(l);
5313 assert(literal_value(s, l) == VAL_TRUE);
5314 assert(s->level[x] == k);
5315 assert(is_var_marked(s, x));
5316 clr_var_mark(s, x);
5317 }
5318 }
5319
5320
5321 /*
5322 * Pop: backtrack to previous base_level
5323 * - can be called after the search terminates or from an idle state
5324 * - should not be called if status is INTERRUPTED or SEARCHING
5325 */
smt_pop(smt_core_t * s)5326 void smt_pop(smt_core_t *s) {
5327 trail_t *top;
5328
5329 /*
5330 * Abort if push_pop is not enabled or if there's no pushed state
5331 */
5332 assert((s->option_flag & PUSH_POP_MASK) != 0 && s->base_level > 0 &&
5333 s->status != STATUS_INTERRUPTED && s->status != STATUS_SEARCHING);
5334
5335 // We need to backtrack before calling the pop function of th_solver
5336 backtrack_to_base_level(s);
5337 s->th_ctrl.pop(s->th_solver);
5338
5339 clear_base_level_marks(s);
5340 top = trail_stack_top(&s->trail_stack);
5341 restore_clauses(s, top->nclauses);
5342 restore_binary_clauses(s, top->nbins);
5343
5344 // the lemma queue may be non-empty so we must clear it here
5345 reset_lemma_queue(&s->lemmas);
5346
5347 s->base_level --;
5348 backtrack(s, s->base_level);
5349 s->nb_unit_clauses = top->nunits;
5350
5351 restore_variables(s, top->nvars);
5352
5353 // restore the propagation pointers
5354 s->stack.prop_ptr = top->prop_ptr;
5355 s->stack.theory_ptr = top->theory_ptr;
5356
5357 trail_stack_pop(&s->trail_stack);
5358
5359 // gate table
5360 gate_table_pop(&s->gates);
5361
5362 // reset status
5363 s->status = STATUS_IDLE;
5364 }
5365
smt_interrupt_push(smt_core_t * s)5366 static void smt_interrupt_push(smt_core_t *s) {
5367 assert (!s->interrupt_push);
5368 smt_push(s);
5369 s->interrupt_push = true;
5370 }
5371
smt_interrupt_pop(smt_core_t * s)5372 static void smt_interrupt_pop(smt_core_t *s) {
5373 if (s->interrupt_push) {
5374 smt_pop(s);
5375 s->interrupt_push = false;
5376 }
5377 }
5378
5379 /*
5380 * Cleanup after search was interrupted or returned unsat
5381 * - the clean state was pushed on the trail stack on start_search
5382 * - we just call pop
5383 */
smt_cleanup(smt_core_t * s)5384 void smt_cleanup(smt_core_t *s) {
5385 assert((s->status == STATUS_INTERRUPTED || s->status == STATUS_UNSAT)
5386 && (s->option_flag & CLEAN_INTERRUPT_MASK) != 0);
5387 s->status = STATUS_IDLE; // make sure pop does not abort
5388 smt_interrupt_pop(s);
5389 }
5390
5391
5392 /*
5393 * Clear the current boolean assignment and reset status to IDLE
5394 */
smt_clear(smt_core_t * s)5395 void smt_clear(smt_core_t *s) {
5396 assert(s->status == STATUS_SAT || s->status == STATUS_UNKNOWN);
5397
5398 // Give a chance to the theory solver to cleanup its own state
5399 s->th_ctrl.clear(s->th_solver);
5400
5401 /*
5402 * In clean-interrupt mode, we restore the state to what it was
5403 * before the search started. This also backtracks to the base_level
5404 * and clears the current assignment.
5405 */
5406 if ((s->option_flag & CLEAN_INTERRUPT_MASK) != 0) {
5407 smt_interrupt_pop(s);
5408 } else {
5409 // no state to restore. Just backtrack and clear the assignment
5410 backtrack_to_base_level(s);
5411 s->status = STATUS_IDLE;
5412 }
5413 }
5414
5415
5416 /*
5417 * Cleanup after unsat.
5418 */
smt_clear_unsat(smt_core_t * s)5419 void smt_clear_unsat(smt_core_t *s) {
5420 smt_status_t saved_status;
5421
5422 assert(s->status == STATUS_UNSAT);
5423 saved_status = STATUS_UNSAT;
5424
5425 /*
5426 * Remove assumptions by backtracking to the base_level
5427 */
5428 if (s->has_assumptions) {
5429 backtrack_to_base_level(s);
5430
5431 // cleanup
5432 s->has_assumptions = false;
5433 s->num_assumptions = 0;
5434 s->assumption_index = 0;
5435 s->assumptions = NULL;
5436 s->bad_assumption = null_literal;
5437
5438 // status returns to IDLE
5439 s->status = STATUS_IDLE;
5440 saved_status = STATUS_IDLE;
5441 }
5442
5443 assert(s->decision_level == s->base_level);
5444
5445 /*
5446 * In clean-interrupt mode, we restore the state to what it was
5447 * before the search started (using pop).
5448 */
5449 if ((s->option_flag & CLEAN_INTERRUPT_MASK) != 0) {
5450 smt_interrupt_pop(s);
5451 s->status = saved_status;
5452 }
5453 }
5454
5455
5456
5457 /*****************
5458 * CHECKPOINTS *
5459 ****************/
5460
5461 /*
5462 * Record current decision level and number of variables
5463 * - any variables created after the checkpoints will
5464 * be deleted when the solver backtracks to a lower decision level
5465 */
smt_checkpoint(smt_core_t * s)5466 void smt_checkpoint(smt_core_t *s) {
5467 assert(s->status == STATUS_SEARCHING ||
5468 s->status == STATUS_INTERRUPTED);
5469 push_checkpoint(&s->checkpoints, s->decision_level, s->nvars);
5470 s->cp_flag = false;
5471 }
5472
5473
5474 /*
5475 * Heuristic for deletion of variables and atoms created on the fly:
5476 *
5477 * The checkpoints divide the boolean variables in disjoint segments
5478 * - the top segment is [n, s->nvars - 1] where n <= nvars
5479 * - each segment is assigned a decision level (the decision level at the
5480 * time the checkpoint was created)
5481 * - the top segment can be deleted if the following conditions are satisfied:
5482 * 1) s->cp_flag is true (i.e., after backtracking)
5483 * 2) the segment level is <= the current decision level in s
5484 * 3) all variables in the segment are unassigned.
5485 * - if these conditions hold, we remove all variables in [n, s->nvars - 1]
5486 * and all the atoms attached to these variable, then we consider the next
5487 * segment in the checkpoint stack.
5488 * - after this, we remove all the clauses that refer to a deleted variables
5489 */
5490
5491
5492 /*
5493 * Attempt to remove the top segment [n, s->nvars - 1]
5494 * - if all variables in this segment are unassigned, then their
5495 * atoms are removed and the function returns true
5496 * - otherwise, the function returns false and does nothing
5497 * Note: it does nothing if n == s->nvars, but returns true in that case.
5498 * The boolean variables are not fully deleted yet.
5499 */
delete_variables(smt_core_t * s,uint32_t n)5500 static bool delete_variables(smt_core_t *s, uint32_t n) {
5501 bvar_t x;
5502 atom_table_t *tbl;
5503 uint32_t m;
5504
5505 assert(n <= s->nvars);
5506
5507 m = s->nvars;
5508 for (x=n; x<m; x++) {
5509 if (bvar_is_assigned(s, x)) return false;
5510 }
5511
5512 // delete the atoms
5513 tbl = &s->atoms;
5514 if (tbl->size < m) {
5515 m = tbl->size;
5516 }
5517 for (x=n; x<m; x++) {
5518 heap_remove(&s->heap, x);
5519 if (tst_bit(tbl->has_atom, x)) {
5520 s->th_smt.delete_atom(s->th_solver, tbl->atom[x]);
5521 remove_atom(tbl, x);
5522 }
5523 }
5524
5525 // update s->nvars and s->nlits
5526 s->nvars = n;
5527 s->nlits = 2 * n;
5528
5529 return true;
5530 }
5531
5532 /*
5533 * Remove all literals >= max in literal vector v
5534 * - assumes that v is non-null
5535 */
cleanup_garbage_in_binary_clause_vector(smt_core_t * s,literal_t * v)5536 static void cleanup_garbage_in_binary_clause_vector(smt_core_t *s, literal_t *v) {
5537 uint32_t i, j;
5538 literal_t l, max;
5539
5540 max = pos_lit(s->nvars);
5541 i = 0;
5542 j = 0;
5543 do {
5544 l = v[i++];
5545 if (l < max) { // keep l
5546 v[j ++] = l;
5547 }
5548 } while (l >= 0); // the end-marker is negative. It's copied too
5549
5550 s->aux_literals += i - j; // number of deleted literals
5551 set_lv_size(v, j - 1);
5552 }
5553
5554
5555 /*
5556 * Remove all binary clauses that contain a removed variable.
5557 * - old_nvar = number of variables before removal
5558 */
remove_garbage_bin_clauses(smt_core_t * s,uint32_t old_nvars)5559 static void remove_garbage_bin_clauses(smt_core_t *s, uint32_t old_nvars) {
5560 literal_t max, l, l0, *v0;
5561 uint32_t i, j, n;
5562 ivector_t *v;
5563
5564 max = pos_lit(s->nvars); // all literals of index >= max are dead
5565
5566 // cleanup the binary_clause vector
5567 v = &s->binary_clauses;
5568 n = v->size;
5569 j = 0;
5570 for (i=0; i<n; i+=2) {
5571 if (v->data[i] < max && v->data[i+1] < max) {
5572 v->data[j] = v->data[i];
5573 v->data[j+1] = v->data[i+1];
5574 j += 2;
5575 }
5576 }
5577
5578 // s->aux_literal counts the number of literals removed
5579 s->aux_literals = 0;
5580
5581 // cleanup the vectors bin[l]
5582 for (l0=max; l0<pos_lit(old_nvars); l0++) {
5583 // l0 is a removed literal
5584 v0 = s->bin[l0];
5585 if (v0 != NULL) {
5586 n = get_lv_size(v0);
5587 for (j=0; j<n; j++) {
5588 l = v0[j];
5589 if (l < max && s->bin[l] != NULL) {
5590 cleanup_garbage_in_binary_clause_vector(s, s->bin[l]);
5591 }
5592 }
5593 delete_literal_vector(v0);
5594 s->bin[l0] = NULL;
5595 s->aux_literals += n;
5596 s->watch[l0] = NULL_LINK; // not strictly necessary
5597 }
5598 }
5599
5600 // update the statistics
5601 s->aux_literals /= 2;
5602 s->stats.bin_clauses_deleted += s->aux_literals;
5603 s->nb_bin_clauses -= s->aux_literals;
5604 }
5605
5606
5607
5608 /*
5609 * Check whether clause cl contains literals >= max
5610 * If it does, mark it for deletion.
5611 * Use s->aux_literals to count the number of literals kept
5612 */
mark_clause_to_remove(smt_core_t * s,clause_t * cl,literal_t max)5613 static void mark_clause_to_remove(smt_core_t *s, clause_t *cl, literal_t max) {
5614 uint32_t i;
5615 literal_t l;
5616
5617 i = 0;
5618 l = cl->cl[i];
5619 while (l >= 0) {
5620 if (l >= max) {
5621 assert(! clause_is_locked(s, cl));
5622 mark_for_removal(cl);
5623 return;
5624 }
5625 i ++;
5626 l = cl->cl[i];
5627 }
5628 s->aux_literals += (i - 1);
5629 }
5630
5631
5632
5633 /*
5634 * Cleanup the problem and learned clauses after removal of variables
5635 */
remove_garbage_clauses(smt_core_t * s)5636 static void remove_garbage_clauses(smt_core_t *s) {
5637 literal_t max;
5638 uint32_t i, j, n;
5639 clause_t **v;
5640
5641 max = pos_lit(s->nvars); // all literals of index >= max are dead
5642
5643 // mark clauses to be deleted
5644 s->aux_literals = 0; // count the number of literals in non-deleted clauses
5645 v = s->problem_clauses;
5646 n = get_cv_size(v);
5647 for (i=0; i<n; i++) {
5648 mark_clause_to_remove(s, v[i], max);
5649 }
5650 s->stats.prob_literals = s->aux_literals;
5651
5652 s->aux_literals = 0;
5653 v = s->learned_clauses;
5654 n = get_cv_size(v);
5655 for (i=0; i<n; i++) {
5656 mark_clause_to_remove(s, v[i], max);
5657 }
5658 s->stats.learned_literals = s->aux_literals;
5659
5660 // clean up watched list for 0 ... nvars-1
5661 cleanup_watch_lists(s);
5662
5663 // delete the problem clauses
5664 v = s->problem_clauses;
5665 n = get_cv_size(v);
5666 j = 0;
5667 for (i=0; i<n; i++) {
5668 if (is_clause_to_be_removed(v[i])) {
5669 delete_clause(v[i]);
5670 } else {
5671 v[j] = v[i];
5672 j++;
5673 }
5674 }
5675 set_cv_size(v, j);
5676 s->nb_clauses -= n - j;
5677 s->stats.prob_clauses_deleted += n - j;
5678
5679 // delete the learned clauses
5680 v = s->learned_clauses;
5681 n = get_cv_size(v);
5682 j = 0;
5683 for (i=0; i<n; i++) {
5684 if (is_clause_to_be_removed(v[i])) {
5685 delete_learned_clause(v[i]);
5686 } else {
5687 v[j] = v[i];
5688 j ++;
5689 }
5690 }
5691 set_cv_size(v, j);
5692 s->nb_clauses -= n - j;
5693 s->stats.learned_clauses_deleted += n - j;
5694 }
5695
5696
5697
5698 /*
5699 * Deletion of irrelevant atoms and variables
5700 */
delete_irrelevant_variables(smt_core_t * s)5701 static void delete_irrelevant_variables(smt_core_t *s) {
5702 uint32_t old_nvars;
5703 checkpoint_stack_t *cp;
5704 checkpoint_t *p;
5705 bool dflag;
5706
5707 old_nvars = s->nvars;
5708
5709 dflag = false; // true if some variables are removed
5710 cp = &s->checkpoints;
5711 for (;;) {
5712 if (empty_checkpoint_stack(cp)) break;
5713 p = top_checkpoint(cp);
5714 if (p->dlevel < s->decision_level) break; // can't delete that segment
5715 if (delete_variables(s, p->nvars)) {
5716 // variables in p->nvars to s->nvars have been removed
5717 dflag = true;
5718 pop_checkpoint(cp);
5719 assert(s->nvars == p->nvars);
5720 } else {
5721 break;
5722 }
5723 }
5724
5725 if (dflag) {
5726 s->th_smt.end_atom_deletion(s->th_solver);
5727 remove_garbage_clauses(s);
5728 remove_garbage_bin_clauses(s, old_nvars);
5729 }
5730 }
5731
5732
5733
5734
5735 /*
5736 * Purge all literals that refer to a dynamic variable
5737 * from the assignment stack.
5738 */
purge_all_dynamic_atoms(smt_core_t * s)5739 static void purge_all_dynamic_atoms(smt_core_t *s) {
5740 checkpoint_stack_t *cp;
5741 literal_t *u, l;
5742 uint32_t base_nvars;
5743 uint32_t i, j, k;
5744 bvar_t x;
5745
5746 assert(s->base_level == s->decision_level &&
5747 s->stack.top == s->stack.prop_ptr &&
5748 s->stack.top == s->stack.theory_ptr &&
5749 s->nb_unit_clauses == s->stack.top);
5750
5751 cp = &s->checkpoints;
5752 if (non_empty_checkpoint_stack(cp)) {
5753 // number of variables to keep = nvars at the bottom checkpoint
5754 base_nvars = cp->data[0].nvars;
5755
5756 // remove all literals whose var is >= base_nvars from
5757 // the assignment stack
5758 u = s->stack.lit;
5759 k = s->stack.top;
5760 j = 0;
5761 for (i=0; i<k; i++) {
5762 l = u[i];
5763 x = var_of(l);
5764 if (x >= base_nvars) {
5765 // variable to delete
5766 s->value[x] = VAL_UNDEF_FALSE;
5767 } else {
5768 // keep l
5769 u[j] = l;
5770 j ++;
5771 }
5772 }
5773
5774 // restore the stack pointers
5775 s->stack.top = j;
5776 s->stack.prop_ptr = j;
5777 s->stack.theory_ptr = j;
5778
5779 s->nb_unit_clauses = j;
5780 }
5781
5782 }
5783
5784
5785
5786
5787 /**********************
5788 * SEARCH FUNCTIONS *
5789 *********************/
5790
5791 /*
5792 * New round of assertions
5793 */
internalization_start(smt_core_t * s)5794 void internalization_start(smt_core_t *s) {
5795 assert(s->status == STATUS_IDLE && s->decision_level == s->base_level);
5796
5797 #if TRACE
5798 printf("\n---> DPLL START\n");
5799 fflush(stdout);
5800 #endif
5801
5802 s->inconsistent = false;
5803 s->theory_conflict = false;
5804 s->conflict = NULL;
5805 s->false_clause = NULL;
5806 s->th_ctrl.start_internalization(s->th_solver);
5807 }
5808
5809
5810 /*
5811 * Propagate at the base level
5812 * - this is used to detect early inconsistencies during internalization
5813 */
base_propagate(smt_core_t * s)5814 bool base_propagate(smt_core_t *s) {
5815 assert(s->status == STATUS_IDLE && s->decision_level == s->base_level);
5816
5817 #if TRACE
5818 printf("\n---> DPLL BASE PROPAGATE\n");
5819 fflush(stdout);
5820 #endif
5821
5822 /*
5823 * If s is inconsistent (i.e., the empty clause was added) then there's
5824 * nothing more to do.
5825 *
5826 * Otherwise, force a call to theory_propagation first
5827 * - this ensures that the theory solver has a chance to detect inconsistencies,
5828 * even if it has not created atoms yet.
5829 * - this is necessary because asserted axioms may be handled directly by
5830 * the solver, without causing literals/atoms to be created in the core.
5831 */
5832 if (!s->inconsistent && theory_propagation(s) && smt_propagation(s)) {
5833 return true;
5834 }
5835
5836 assert(s->inconsistent);
5837 s->status = STATUS_UNSAT;
5838 return false;
5839 }
5840
5841 /*
5842 * Prepare for the search:
5843 * - a = optional array of assumptions
5844 * - n = number of assumptions
5845 * - a[0 ... n-1] must all be valid literals in the core
5846 *
5847 * Effect:
5848 * - initialize variable heap
5849 * - store a pointer to the assumption array
5850 * - make an internal copy of the assumptions
5851 * - initialize variable heap
5852 * - set status to searching
5853 * - if clean_interrupt is enabled, save the current state to
5854 * enable cleanup after interrupt (this uses push)
5855 */
start_search(smt_core_t * s,uint32_t n,const literal_t * a)5856 void start_search(smt_core_t *s, uint32_t n, const literal_t *a) {
5857 assert(s->status == STATUS_IDLE && s->decision_level == s->base_level);
5858
5859 #if TRACE
5860 printf("\n---> DPLL START\n");
5861 fflush(stdout);
5862 #endif
5863
5864 if ((s->option_flag & CLEAN_INTERRUPT_MASK) != 0) {
5865 /*
5866 * in clean-interrupt mode, save the current state so
5867 * that it can be restored after a call to stop_search.
5868 */
5869 smt_interrupt_push(s);
5870 }
5871
5872 s->status = STATUS_SEARCHING;
5873 s->inconsistent = false;
5874 s->theory_conflict = false;
5875 s->conflict = NULL;
5876 s->false_clause = NULL;
5877
5878 s->stats.restarts = 0;
5879 s->stats.simplify_calls = 0;
5880 s->stats.reduce_calls = 0;
5881 s->stats.decisions = 0;
5882 s->stats.random_decisions = 0;
5883 s->stats.conflicts = 0;
5884 s->simplify_bottom = 0;
5885 s->simplify_props = 0;
5886 s->simplify_threshold = 0;
5887
5888 s->has_assumptions = (n > 0);
5889 s->num_assumptions = n;
5890 s->assumption_index = 0;
5891 s->assumptions = a;
5892 s->bad_assumption = null_literal;
5893
5894 /*
5895 * Allow theory solver to do whatever initializations it needs
5896 */
5897 s->th_ctrl.start_search(s->th_solver);
5898
5899 #if DEBUG
5900 check_heap_content(s);
5901 check_heap(s);
5902 #endif
5903 }
5904
5905
5906 /*
5907 * Stop the search: set status to interrupted
5908 * - this can be called from a signal handler to interrupt the solver
5909 * - if clean_interrupt is enabled, the state at start_search can be restored by
5910 * calling smt_cleanup(s)
5911 */
stop_search(smt_core_t * s)5912 void stop_search(smt_core_t *s) {
5913 if (s->status == STATUS_SEARCHING) {
5914 s->status = STATUS_INTERRUPTED;
5915 }
5916 }
5917
5918
5919 /*
5920 * Core solving function.
5921 *
5922 * It executes the following loop:
5923 * 1) if lemmas are present, integrate them to the clause database
5924 * 2) perform boolean and theory propagation
5925 * 3) if a conflict is found, resolve that conflict otherwise
5926 * exit the loop.
5927 * 4) after a conflict is resolved, check whether the bound max_conflict
5928 * is reached. If so exit.
5929 *
5930 * Output:
5931 * - true on normal exit
5932 * - false on early exit (i.e., max_conflict reached)
5933 */
smt_core_process(smt_core_t * s,uint64_t max_conflicts)5934 static bool smt_core_process(smt_core_t *s, uint64_t max_conflicts) {
5935 while (s->status == STATUS_SEARCHING) {
5936 if (s->inconsistent) {
5937 resolve_conflict(s);
5938 if (s->inconsistent) {
5939 // conflict could not be resolved: unsat problem
5940 // the lemma queue may be non-empty so we must clear it here
5941 reset_lemma_queue(&s->lemmas);
5942 s->status = STATUS_UNSAT;
5943 }
5944 // decay activities after every conflict
5945 s->cla_inc *= s->inv_cla_decay;
5946 s->heap.act_increment *= s->heap.inv_act_decay;
5947
5948 // exit if max_conflict reached
5949 if (num_conflicts(s) >= max_conflicts) {
5950 return false;
5951 }
5952
5953 } else if (s->cp_flag) {
5954 delete_irrelevant_variables(s);
5955 s->cp_flag = false;
5956
5957 } else if (! empty_lemma_queue(&s->lemmas)) {
5958 add_all_lemmas(s);
5959
5960 } else {
5961 /*
5962 * propagation can create a conflict or add lemmas.
5963 * if it doesn't we're done.
5964 */
5965 if (smt_propagation(s) && empty_lemma_queue(&s->lemmas)) break;
5966 }
5967 }
5968
5969 // try to simplify at the base level
5970 if (s->status == STATUS_SEARCHING &&
5971 s->decision_level == s->base_level &&
5972 s->stack.top > s->simplify_bottom &&
5973 s->stats.propagations >= s->simplify_props + s->simplify_threshold) {
5974 simplify_clause_database(s);
5975 }
5976
5977 return true;
5978 }
5979
5980
5981
5982 /*
5983 * Process with no conflict bounds
5984 */
smt_process(smt_core_t * s)5985 void smt_process(smt_core_t *s) {
5986 (void) smt_core_process(s, UINT64_MAX);
5987 }
5988
5989 /*
5990 * Use a bound
5991 */
smt_bounded_process(smt_core_t * s,uint64_t max_conflicts)5992 bool smt_bounded_process(smt_core_t *s, uint64_t max_conflicts) {
5993 return smt_core_process(s, max_conflicts);
5994 }
5995
5996
5997
5998
5999 /*
6000 * End-of-search check: delayed theory solving:
6001 * - call the final_check function of the theory solver
6002 * - if that creates new variables or lemmas or report a conflict
6003 * then smt_process is called
6004 * - otherwise the core status is updated to SAT or UNKNOWN and the search
6005 * is done.
6006 */
smt_final_check(smt_core_t * s)6007 void smt_final_check(smt_core_t *s) {
6008 assert(s->status == STATUS_SEARCHING || s->status == STATUS_INTERRUPTED);
6009
6010 if (s->status == STATUS_SEARCHING) {
6011 switch (s->th_ctrl.final_check(s->th_solver)) {
6012 case FCHECK_CONTINUE:
6013 /*
6014 * deal with conflicts or lemmas if any.
6015 * leave status as it is so that the search can proceed
6016 */
6017 smt_process(s);
6018 break;
6019 /*
6020 * Otherwise: update status to stop the search
6021 */
6022 case FCHECK_SAT:
6023 s->status = STATUS_SAT;
6024 break;
6025 case FCHECK_UNKNOWN:
6026 s->status = STATUS_UNKNOWN;
6027 break;
6028 }
6029 }
6030 }
6031
6032
6033
6034 /*
6035 * Search for a satisfiable assignment.
6036 * - stop on the first conflict and return false
6037 * - return true if all Boolean variables are assigned.
6038 */
smt_easy_sat(smt_core_t * s)6039 bool smt_easy_sat(smt_core_t *s) {
6040 literal_t l;
6041
6042 assert(s->bool_only);
6043
6044 for (;;) {
6045 assert(s->status == STATUS_SEARCHING || s->status == STATUS_INTERRUPTED);
6046 smt_propagation(s);
6047 assert(empty_lemma_queue(&s->lemmas));
6048 assert(! s->cp_flag);
6049
6050 if (s->inconsistent) {
6051 // clear the conflict
6052 backtrack_to_base_level(s);
6053 s->inconsistent = false;
6054 s->theory_conflict = false;
6055 return false;
6056 }
6057
6058 l = select_unassigned_literal(s);
6059 if (l == null_literal) {
6060 s->status = STATUS_SAT;
6061 return true;
6062 }
6063 decide_literal(s, l);
6064 }
6065 }
6066
6067
6068
6069
6070 /***************
6071 * RESTARTS *
6072 **************/
6073
6074 /*
6075 * Three variants of restart:
6076 * - full restart: backtrack to the base_level
6077 * - partial restart: lazier version: backtrack(s, k) for some
6078 * level k >= base_level determined by variable activities:
6079 * - partial_restart_var: even lazier version: if partial restart
6080 * would backtrack to level k then partial_restart_var backtracks
6081 * to k' >= k.
6082 * - benchmarking shows that partial_restart_var seems to work best.
6083 */
6084
6085 /*
6086 * Cleanup the heap to prepare for a partial restart:
6087 * - remove variables until the top var is unassigned
6088 * or until the heap is empty
6089 */
cleanup_heap(smt_core_t * s)6090 static void cleanup_heap(smt_core_t *s) {
6091 var_heap_t *heap;
6092 bvar_t x;
6093
6094 heap = &s->heap;
6095 while (! heap_is_empty(heap)) {
6096 x = heap->heap[1];
6097 if (bvar_is_unassigned(s, x)) {
6098 break;
6099 }
6100 assert(x >= 0 && heap->heap_last > 0);
6101 heap->heap_index[x] = -1;
6102 update_down(heap, 1);
6103 }
6104 }
6105
6106
6107 /*
6108 * Check whether all variables assigned at level k have
6109 * activity less than ax
6110 */
level_has_lower_activity(smt_core_t * s,double ax,uint32_t k)6111 static bool level_has_lower_activity(smt_core_t *s, double ax, uint32_t k) {
6112 prop_stack_t *stack;
6113 uint32_t i, n;
6114 bvar_t x;
6115
6116 assert(s->base_level <= k && k <= s->decision_level);
6117
6118 stack = &s->stack;
6119
6120 // i := start of level k
6121 // n := end of level k
6122 i = stack->level_index[k];
6123 n = stack->top;
6124 if (k < s->decision_level) {
6125 n = stack->level_index[k+1];
6126 }
6127
6128 while (i < n) {
6129 x = var_of(stack->lit[i]);
6130 assert(bvar_is_assigned(s, x) && s->level[x] == k);
6131 if (s->heap.activity[x] >= ax) {
6132 return false;
6133 }
6134 i ++;
6135 }
6136
6137 return true;
6138 }
6139
6140
6141 /*
6142 * Do a full restart: backtrack to base_level
6143 */
full_restart(smt_core_t * s)6144 static void full_restart(smt_core_t *s) {
6145 assert(s->base_level < s->decision_level);
6146
6147 backtrack(s, s->base_level);
6148 s->th_ctrl.backtrack(s->th_solver, s->base_level);
6149 // clear the checkpoints
6150 if (s->cp_flag) {
6151 purge_all_dynamic_atoms(s);
6152 }
6153 }
6154
6155 /*
6156 * Partial restart: backtrack to level k
6157 */
partial_restart(smt_core_t * s,uint32_t k)6158 static void partial_restart(smt_core_t *s, uint32_t k) {
6159 assert(s->base_level <= k && k < s->decision_level);
6160
6161 backtrack(s, k);
6162 s->th_ctrl.backtrack(s->th_solver, k);
6163 }
6164
6165
6166 /*
6167 * Full restart: cause s and the theory solver to backtrack to base_level
6168 * (do nothing if decision_level == base_level)
6169 */
smt_restart(smt_core_t * s)6170 void smt_restart(smt_core_t *s) {
6171
6172 assert(s->status == STATUS_SEARCHING || s->status == STATUS_INTERRUPTED);
6173
6174 #if TRACE
6175 printf("\n---> DPLL RESTART\n");
6176 #endif
6177 s->stats.restarts ++;
6178 if (s->base_level < s->decision_level) {
6179 full_restart(s);
6180 }
6181 }
6182
6183
6184 /*
6185 * Partial restart: attempt to reuse the assignment stack
6186 * - find the unassigned variable of highest activity
6187 * - keep all current decisions that have an activity higher than that
6188 */
smt_partial_restart(smt_core_t * s)6189 void smt_partial_restart(smt_core_t *s) {
6190 double ax;
6191 bvar_t x;
6192 uint32_t i, k, n;
6193
6194 assert(s->status == STATUS_SEARCHING || s->status == STATUS_INTERRUPTED);
6195
6196 #if TRACE
6197 printf("\n---> DPLL PARTIAL RESTART\n");
6198 #endif
6199
6200 s->stats.restarts ++;
6201
6202 if (s->base_level < s->decision_level) {
6203 cleanup_heap(s);
6204 if (heap_is_empty(&s->heap)) {
6205 full_restart(s);
6206 } else {
6207 // x = most active unassigned variable
6208 // ax = its activity
6209 x = s->heap.heap[1];
6210 assert(x >= 0 && bvar_is_unassigned(s, x));
6211 ax = s->heap.activity[x];
6212
6213 /*
6214 * search for the first level i whose decision level has
6215 * activity less than ax, then backtrack to level i-1.
6216 */
6217 n = s->decision_level;
6218 for (i=s->base_level+1; i<=n; i++) {
6219 k = s->stack.level_index[i];
6220 x = var_of(s->stack.lit[k]); // decision variable for level i
6221 assert(bvar_is_assigned(s, x) &&
6222 s->level[x] == i &&
6223 s->antecedent[x] == mk_literal_antecedent(null_literal));
6224
6225 if (s->heap.activity[x] < ax) {
6226 partial_restart(s, i - 1);
6227 break;
6228 }
6229 }
6230 }
6231 }
6232 }
6233
6234
6235 /*
6236 * Variant:
6237 * - find the unassigned variable of highest activity
6238 * - keep all current decision levels that have at least one variable
6239 * with higher activity than that
6240 */
smt_partial_restart_var(smt_core_t * s)6241 void smt_partial_restart_var(smt_core_t *s) {
6242 double ax;
6243 bvar_t x;
6244 uint32_t i, n;
6245
6246 assert(s->status == STATUS_SEARCHING || s->status == STATUS_INTERRUPTED);
6247
6248 #if TRACE
6249 printf("\n---> DPLL PARTIAL RESTART (VARIANT)\n");
6250 #endif
6251
6252 s->stats.restarts ++;
6253 if (s->base_level < s->decision_level) {
6254 cleanup_heap(s);
6255 if (heap_is_empty(&s->heap)) {
6256 full_restart(s);
6257 } else {
6258 x = s->heap.heap[1];
6259 assert(x >= 0 && bvar_is_unassigned(s, x));
6260 ax = s->heap.activity[x];
6261
6262 n = s->decision_level;
6263 for (i=s->base_level+1; i<=n; i++) {
6264 if (level_has_lower_activity(s, ax, i)) {
6265 partial_restart(s, i - 1);
6266 break;
6267 }
6268 }
6269 }
6270 }
6271 }
6272
6273
6274
6275
6276
6277
6278 /*******************
6279 * CHECK CLAUSES *
6280 ******************/
6281
6282 /*
6283 * Check whether all binary clauses are true in the current assignment
6284 */
all_binary_clauses_are_true(smt_core_t * s)6285 static bool all_binary_clauses_are_true(smt_core_t *s) {
6286 literal_t l0, l, *v;
6287
6288 for (l0=0; l0<s->nlits; l0++) {
6289 if (literal_value(s, l0) != VAL_TRUE) {
6290 // check whether l is true for all binary clauses {l0, l}
6291 v = s->bin[l0];
6292 if (v != NULL) {
6293 // this loop terminates with l<0 (end-marker) if all clauses {l0, l} are true
6294 do {
6295 l = *v ++;
6296 } while (l >= 0 && literal_value(s, l) == VAL_TRUE);
6297 if (l >= 0) return false;
6298 }
6299 }
6300 }
6301
6302 return true;
6303 }
6304
6305
6306 /*
6307 * Check whether clause cl is true
6308 */
clause_is_true(smt_core_t * s,clause_t * cl)6309 static bool clause_is_true(smt_core_t *s, clause_t *cl) {
6310 uint32_t i;
6311 literal_t l;
6312
6313 i = 0;
6314 do {
6315 l = cl->cl[i];
6316 i ++;
6317 if (literal_value(s, l) == VAL_TRUE) return true;
6318 } while (l >= 0);
6319
6320 return false;
6321 }
6322
6323
6324 /*
6325 * Check whether all problem clauses are true
6326 */
all_problem_clauses_are_true(smt_core_t * s)6327 static bool all_problem_clauses_are_true(smt_core_t *s) {
6328 uint32_t i, n;
6329 clause_t **v;
6330
6331 v = s->problem_clauses;
6332 n = get_cv_size(v);
6333 for (i=0; i<n; i++) {
6334 if (! clause_is_true(s, v[i])) return false;
6335 }
6336
6337 return true;
6338 }
6339
6340
6341 /*
6342 * Check whether all problem clauses are true in the current assignment
6343 */
all_clauses_true(smt_core_t * s)6344 bool all_clauses_true(smt_core_t *s) {
6345 return all_binary_clauses_are_true(s) && all_problem_clauses_are_true(s);
6346 }
6347
6348
6349
6350
6351 /*******************************************
6352 * MODEL GENERATION/LITERAL ASSIGNMENTS *
6353 ******************************************/
6354
6355 /*
6356 * Collect all true literals in vector v
6357 */
collect_true_literals(smt_core_t * s,ivector_t * v)6358 void collect_true_literals(smt_core_t *s, ivector_t *v) {
6359 uint32_t i, n;
6360 literal_t *lit;
6361
6362 ivector_reset(v);
6363
6364 lit = s->stack.lit;
6365 n = s->stack.top;
6366 for (i=0; i<n; i++) {
6367 ivector_push(v, lit[i]);
6368 }
6369 }
6370
6371
6372 /*
6373 * Collect all the decision literals: store them in v
6374 */
collect_decision_literals(smt_core_t * s,ivector_t * v)6375 void collect_decision_literals(smt_core_t *s, ivector_t *v) {
6376 uint32_t i, k, n;
6377 literal_t *lit;
6378
6379 ivector_reset(v);
6380
6381 lit = s->stack.lit;
6382 n = s->decision_level;
6383 for (k=s->base_level+1; k<=n; k++) {
6384 i = s->stack.level_index[k];
6385 ivector_push(v, lit[i]);
6386 }
6387 }
6388
6389
6390 /******************
6391 * IMPORT A MODEL *
6392 *****************/
6393
6394 /*
6395 * Sets the value of variable x
6396 */
set_bvar_value(smt_core_t * s,bvar_t x,bval_t val)6397 void set_bvar_value(smt_core_t *s, bvar_t x, bval_t val) {
6398 assert(0 <= x && x < s->nvars);
6399 s->value[x] = val;
6400 }
6401
6402
6403 /**************************************
6404 * CHECK WHETHER THE CONTEXT IS EMPTY *
6405 *************************************/
6406
6407 /*
6408 * Check whether the core is trivially SAT
6409 * - i.e., check whether there are no problem clauses
6410 */
smt_trivially_sat(smt_core_t * s)6411 bool smt_trivially_sat(smt_core_t *s) {
6412 return num_prob_clauses(s) + num_binary_clauses(s) + num_unit_clauses(s) == 0;
6413 }
6414
6415
6416
6417
6418 /****************************
6419 * UNCONSTRAINED VARIABLES *
6420 ***************************/
6421
6422 /*
6423 * Initialized fv structure:
6424 * - n = number of variables
6425 */
init_free_bool_vars(free_bool_vars_t * fv,uint32_t n)6426 void init_free_bool_vars(free_bool_vars_t *fv, uint32_t n) {
6427 fv->free = safe_malloc(n * sizeof(uint8_t));
6428 fv->nvars = n;
6429 }
6430
6431 /*
6432 * Delete fv
6433 */
delete_free_bool_vars(free_bool_vars_t * fv)6434 void delete_free_bool_vars(free_bool_vars_t *fv) {
6435 safe_free(fv->free);
6436 fv->free = NULL;
6437 }
6438
6439 /*
6440 * Mark var_of(l) as not free in fv
6441 */
mark_lit_not_free(free_bool_vars_t * fv,literal_t l)6442 static inline void mark_lit_not_free(free_bool_vars_t *fv, literal_t l) {
6443 bvar_t x;
6444
6445 x = var_of(l);
6446 assert(0 <= x && x < fv->nvars);
6447 fv->free[x] = false;
6448 }
6449
6450 /*
6451 * Collect all the vars occurring in a unit clause
6452 */
collect_vars_in_unit_clauses(free_bool_vars_t * fv,const smt_core_t * s)6453 static void collect_vars_in_unit_clauses(free_bool_vars_t *fv, const smt_core_t *s) {
6454 uint32_t i, n;
6455 literal_t l;
6456
6457 n = s->stack.top;
6458 if (s->decision_level >= 1) {
6459 n = s->stack.level_index[1];
6460 }
6461 for (i=0; i<n; i++) {
6462 l = s->stack.lit[i];
6463 assert(literal_is_assigned(s, l));
6464 mark_lit_not_free(fv, l);
6465 }
6466 }
6467
6468 /*
6469 * Collect all vars in the binary clauses
6470 * - mark then as constrained
6471 */
collect_vars_in_binary_clauses(free_bool_vars_t * fv,const smt_core_t * s)6472 static void collect_vars_in_binary_clauses(free_bool_vars_t *fv, const smt_core_t *s) {
6473 literal_t l0, l, *v;
6474
6475 for (l0=0; l0 < s->nlits; l0++) {
6476 v = s->bin[l0];
6477 if (v != NULL) {
6478 for (;;) {
6479 l = *v ++;
6480 if (l < 0) break;
6481 mark_lit_not_free(fv, l);
6482 }
6483 }
6484 }
6485 }
6486
6487 /*
6488 * Collect all vars in clause cl
6489 */
collect_vars_in_clause(free_bool_vars_t * fv,const clause_t * cl)6490 static void collect_vars_in_clause(free_bool_vars_t *fv, const clause_t *cl) {
6491 uint32_t i;
6492 literal_t l;
6493
6494 i = 0;
6495 for (;;) {
6496 l = cl->cl[i];
6497 if (l < 0) break;
6498 mark_lit_not_free(fv, l);
6499 i ++;
6500 }
6501 }
6502
6503 /*
6504 * Collect the variables that occur in a problem clause
6505 */
collect_vars_in_problem_clauses(free_bool_vars_t * fv,const smt_core_t * s)6506 static void collect_vars_in_problem_clauses(free_bool_vars_t *fv, const smt_core_t *s) {
6507 uint32_t i, n;
6508 clause_t **v;
6509
6510 v = s->problem_clauses;
6511 n = get_cv_size(v);
6512 for (i=0; i<n; i++) {
6513 collect_vars_in_clause(fv, v[i]);
6514 }
6515 }
6516
6517 /*
6518 * Collect all the free variables in a solver s
6519 * - store them in fv
6520 * - fv must be initialized and large enough to store
6521 * all the variables of s
6522 */
collect_free_bool_vars(free_bool_vars_t * fv,const smt_core_t * s)6523 void collect_free_bool_vars(free_bool_vars_t *fv, const smt_core_t *s) {
6524 uint32_t i, n;
6525
6526 assert(s->nvars <= fv->nvars);
6527
6528 n = fv->nvars;
6529 for (i=0; i<n; i++) {
6530 fv->free[i] = true;
6531 }
6532
6533 mark_lit_not_free(fv, true_literal);
6534 collect_vars_in_unit_clauses(fv, s);
6535 collect_vars_in_binary_clauses(fv, s);
6536 collect_vars_in_problem_clauses(fv, s);
6537 }
6538
6539
6540
6541
6542
6543 /*************************
6544 * DEBUGGING FUNCTIONS *
6545 ************************/
6546
6547 #if DEBUG
6548
6549 /*
6550 * Check that all unassigned variables are in the heap
6551 */
check_heap_content(smt_core_t * s)6552 static void check_heap_content(smt_core_t *s) {
6553 uint32_t x;
6554
6555 if (s->heap.size < s->nvars) {
6556 printf("ERROR: incorrect heap: heap_size is smaller than the number of variables\n");
6557 fflush(stdout);
6558 return;
6559 }
6560
6561 for (x=0; x<s->nvars; x++) {
6562 if (bval_is_undef(s->value[x]) && s->heap.heap_index[x] < 0) {
6563 printf("ERROR: incorrect heap: unassigned variable %"PRIu32" is not in the heap\n", x);
6564 fflush(stdout);
6565 }
6566 }
6567 }
6568
6569
6570 /*
6571 * Check that the heap is correct
6572 */
check_heap(smt_core_t * s)6573 static void check_heap(smt_core_t *s) {
6574 double *act;
6575 bvar_t *h, x;
6576 int32_t *index;
6577 uint32_t j, k, last;
6578
6579 h = s->heap.heap;
6580 index = s->heap.heap_index;
6581 act = s->heap.activity;
6582 last = s->heap.heap_last;
6583
6584 for (j=1; j<=last; j++) {
6585 x = h[j];
6586 if (index[x] != j) {
6587 printf("ERROR: incorrect heap: inconsistent index for variable %"PRId32"\n", x);
6588 printf(" heap_index is %"PRId32", should be %"PRIu32"\n", index[x], j);
6589 fflush(stdout);
6590 }
6591
6592 k = j>>1;
6593 if (k < j && act[h[k]] < act[x]) {
6594 // if (k < j && heap_precedes(act, x, h[k])) {
6595 printf("ERROR: incorrect heap order: child %"PRIu32" has higher activity than its parent %"PRIu32"\n", j, k);
6596 fflush(stdout);
6597 }
6598 }
6599 }
6600
6601
6602
6603 /*
6604 * Check propagation results
6605 */
check_propagation_bin(smt_core_t * s,literal_t l0)6606 static void check_propagation_bin(smt_core_t *s, literal_t l0) {
6607 literal_t l1, *v;
6608
6609 v = s->bin[l0];
6610 if (v == NULL || literal_value(s, l0) != VAL_FALSE) return;
6611
6612 l1 = *v ++;
6613 while (l1 >= 0) {
6614 if (literal_is_unassigned(s, l1)) {
6615 printf("ERROR: missed propagation. Binary clause {%"PRId32", %"PRId32"}\n", l0, l1);
6616 } else if (literal_value(s, l1) == VAL_FALSE) {
6617 printf("ERROR: missed conflict. Binary clause {%"PRId32", %"PRId32"}\n", l0, l1);
6618 }
6619 l1 = *v ++;
6620 }
6621 }
6622
indicator(bval_t v,bval_t c)6623 static inline int32_t indicator(bval_t v, bval_t c) {
6624 return (v == c) ? 1 : 0;
6625 }
6626
check_watch_list(smt_core_t * s,literal_t l,clause_t * cl)6627 static void check_watch_list(smt_core_t *s, literal_t l, clause_t *cl) {
6628 link_t lnk;
6629
6630 for (lnk = s->watch[l]; lnk != NULL_LINK; lnk = next_of(lnk)) {
6631 if (clause_of(lnk) == cl) {
6632 return;
6633 }
6634 }
6635
6636 printf("ERROR: missing watch, literal = %"PRId32", clause = %p\n", l, clause_of(lnk));
6637 }
6638
6639
check_propagation_clause(smt_core_t * s,clause_t * cl)6640 static void check_propagation_clause(smt_core_t *s, clause_t *cl) {
6641 literal_t l0, l1, l;
6642 literal_t *d;
6643 int32_t nf, nt, nu;
6644 uint32_t i;
6645 bval_t v;
6646
6647 nf = 0;
6648 nt = 0;
6649 nu = 0;
6650
6651 l0 = get_first_watch(cl);
6652 v = literal_value(s, l0);
6653 nf += indicator(v, VAL_FALSE);
6654 nt += indicator(v, VAL_TRUE);
6655 nu += indicator(v, VAL_UNDEF_FALSE) + indicator(v, VAL_UNDEF_TRUE);
6656
6657 l1 = get_second_watch(cl);
6658 v = literal_value(s, l1);
6659 nf += indicator(v, VAL_FALSE);
6660 nt += indicator(v, VAL_TRUE);
6661 nu += indicator(v, VAL_UNDEF_FALSE) + indicator(v, VAL_UNDEF_TRUE);
6662
6663 d = cl->cl;
6664 i = 2;
6665 l = d[i];
6666 while (l >= 0) {
6667 v = literal_value(s, l);
6668 nf += indicator(v, VAL_FALSE);
6669 nt += indicator(v, VAL_TRUE);
6670 nu += indicator(v, VAL_UNDEF_FALSE) + indicator(v, VAL_UNDEF_TRUE);
6671
6672 i ++;
6673 l = d[i];
6674 }
6675
6676 if (nt == 0 && nu == 0) {
6677 printf("ERROR: missed conflict. Clause {%"PRId32", %"PRId32"", l0, l1);
6678 i = 2;
6679 l = d[i];
6680 while (l >= 0) {
6681 printf(", %"PRId32"", l);
6682 i ++;
6683 l = d[i];
6684 }
6685 printf("} (addr = %p)\n", cl);
6686 }
6687
6688 if (nt == 0 && nu == 1) {
6689 printf("ERROR: missed propagation. Clause {%"PRId32", %"PRId32"", l0, l1);
6690 i = 2;
6691 l = d[i];
6692 while (l >= 0) {
6693 printf(", %"PRId32"", l);
6694 i ++;
6695 l = d[i];
6696 }
6697 printf("} (addr = %p)\n", cl);
6698 }
6699
6700 check_watch_list(s, l0, cl);
6701 check_watch_list(s, l1, cl);
6702 }
6703
check_propagation(smt_core_t * s)6704 static void check_propagation(smt_core_t *s) {
6705 literal_t l0;
6706 uint32_t i, n;
6707 clause_t **v;
6708
6709 for (l0=0; l0<s->nlits; l0++) {
6710 check_propagation_bin(s, l0);
6711 }
6712
6713 v = s->problem_clauses;
6714 n = get_cv_size(v);
6715 for (i=0; i<n; i++) {
6716 if (! is_clause_to_be_removed(v[i])) {
6717 check_propagation_clause(s, v[i]);
6718 }
6719 }
6720
6721 v = s->learned_clauses;
6722 n = get_cv_size(v);
6723 for (i=0; i<n; i++) check_propagation_clause(s, v[i]);
6724 }
6725
6726
6727
6728 /*
6729 * Check that marks/levels and assignments are consistent
6730 */
check_marks(smt_core_t * s)6731 static void check_marks(smt_core_t *s) {
6732 uint32_t i, n;
6733 bvar_t x;
6734 literal_t l;
6735
6736 for (x=0; x<s->nvars; x++) {
6737 if (is_var_marked(s, x) && s->level[x] > s->base_level) {
6738 printf("Warning: var %"PRId32" marked but level[%"PRId32"] = %"PRIu32"\n", x, x, s->level[x]);
6739 fflush(stdout);
6740 }
6741 }
6742
6743 n = s->nb_unit_clauses;
6744 for (i=0; i<n; i++) {
6745 l = s->stack.lit[i];
6746 if (is_lit_unmarked(s, l)) {
6747 printf("Warning: literal %"PRId32" assigned at level %"PRIu32" but not marked\n",
6748 l, s->level[var_of(l)]);
6749 fflush(stdout);
6750 }
6751 }
6752 }
6753
6754
6755 /*
6756 * Auxiliary function: print array of literal as a clause (array a)
6757 * - a must be terminated by null_literal
6758 */
print_literal_array(literal_t * a)6759 static void print_literal_array(literal_t *a) {
6760 uint32_t i;
6761 literal_t l;
6762
6763 printf("{");
6764 i = 0;
6765 l = a[i];
6766 while (l >= 0) {
6767 printf(" ");
6768 print_literal(stdout, l);
6769 i ++;
6770 l = a[i];
6771 }
6772 printf(" }");
6773 }
6774
6775 /*
6776 * Check that all literals in a are false (theory conflict)
6777 * - a must be terminated by null_literal
6778 */
check_theory_conflict(smt_core_t * s,literal_t * a)6779 static void check_theory_conflict(smt_core_t *s, literal_t *a) {
6780 uint32_t i;
6781 literal_t l;
6782
6783 i = 0;
6784 l = a[i];
6785 while (l >= 0) {
6786 if (literal_value(s, l) != VAL_FALSE) {
6787 printf("Warning: invalid theory conflict. Literal %"PRId32" is not false\n", l);
6788 printf("Conflict: ");
6789 print_literal_array(a);
6790 printf("\n");
6791 fflush(stdout);
6792 return;
6793 }
6794 i ++;
6795 l = a[i];
6796 }
6797 }
6798
6799 /*
6800 * Auxiliary function: if flag is true, print warning message when v
6801 * is an invalid explanation.
6802 */
print_theory_explanation_warning(ivector_t * v,literal_t l0,bool * flag)6803 static void print_theory_explanation_warning(ivector_t *v, literal_t l0, bool *flag) {
6804 uint32_t i;
6805 literal_t l;
6806
6807 if (*flag) {
6808 printf("\nWarning: invalid theory explanation:");
6809 for (i=0; i<v->size; i++) {
6810 l = v->data[i];
6811 printf(" ");
6812 print_literal(stdout, l);
6813 }
6814 printf(" for ");
6815 print_literal(stdout, l0);
6816 printf("\n");
6817 *flag = false;
6818 }
6819 }
6820
6821 /*
6822 * Return true if l0 is before l in the assignment queue
6823 * both must have the same decision level k
6824 */
check_precedence(smt_core_t * s,literal_t l0,literal_t l)6825 static bool check_precedence(smt_core_t *s, literal_t l0, literal_t l) {
6826 uint32_t k, i;
6827 literal_t l1;
6828
6829 if (l0 == l) return false;
6830
6831 k = d_level(s, l0);
6832 assert(k == d_level(s, l));
6833 i = s->stack.level_index[k];
6834 for (;;) {
6835 assert(i < s->stack.top);
6836 l1 = s->stack.lit[i];
6837 assert(d_level(s, l1) == k);
6838 if (l1 == l0) return true;
6839 if (l1 == l) return false;
6840 i ++;
6841 }
6842 }
6843
6844 /*
6845 * Check causality on theory explanations:
6846 * - l: literal assigned by theory propagation
6847 * - s->explanation: literals that imply l
6848 * (s->explanation is interpreted as a conjunction of literals)
6849 * all literals in explanation must be before l in the assignment stack
6850 */
check_theory_explanation(smt_core_t * s,literal_t l)6851 static void check_theory_explanation(smt_core_t *s, literal_t l) {
6852 uint32_t i, n, k;
6853 literal_t l0;
6854 bool print;
6855
6856 k = d_level(s, l);
6857 n = s->explanation.size;
6858 print = true;
6859 for (i=0; i<n; i++) {
6860 l0 = s->explanation.data[i];
6861
6862 if (literal_value(s, l0) != VAL_TRUE) {
6863 print_theory_explanation_warning(&s->explanation, l, &print);
6864 printf("Literal %"PRId32" should be true\n", l0);
6865
6866 } else if (d_level(s, l0) > k) {
6867 print_theory_explanation_warning(&s->explanation, l, &print);
6868 printf("Literal %"PRId32" has higher decision level than %"PRId32"\n", l0, l);
6869
6870 } else if (d_level(s, l0) == k && ! check_precedence(s, l0, l)) {
6871 print_theory_explanation_warning(&s->explanation, l, &print);
6872 printf("Literal %"PRId32" is after %"PRId32" in the assignment queue\n", l0, l);
6873
6874 }
6875 }
6876 if (print) {
6877 fflush(stdout);
6878 }
6879 }
6880
6881
6882 /*
6883 * Check whether a[0] and a[1] are valid watched literals for
6884 * the clause a[0] ... a[n-1]. (n >= 2)
6885 */
print_lit_val_level(literal_t l,bval_t v,uint32_t k)6886 static void print_lit_val_level(literal_t l, bval_t v, uint32_t k) {
6887 printf("---> ");
6888 print_literal(stdout, l);
6889 printf(": value = ");
6890 print_bval(stdout, v);
6891 if (bval_is_def(v)) {
6892 printf(" at level %"PRIu32, k);
6893 }
6894 printf("\n");
6895 }
6896
6897 /*
6898 * Check whether (v1, k1) must be preferred to (v2, k2)
6899 * - rule1: (undef, _) < (false, _)
6900 * - rule2: k2 < k1 implies (false, k1) < (false, k2)
6901 */
check_prefer(bval_t v1,uint32_t k1,bval_t v2,uint32_t k2)6902 static bool check_prefer(bval_t v1, uint32_t k1, bval_t v2, uint32_t k2) {
6903 return (bval_is_undef(v1) && v2 == VAL_FALSE)
6904 || (v1 == VAL_FALSE && v2 == VAL_FALSE && k1 > k2);
6905 }
6906
check_watched_literals(smt_core_t * s,uint32_t n,literal_t * a)6907 static void check_watched_literals(smt_core_t *s, uint32_t n, literal_t *a) {
6908 literal_t l;
6909 bval_t v0, v1, v;
6910 uint32_t k0, k1, k, i;
6911
6912 l = a[0];
6913 v0 = literal_value(s, l);
6914 k0 = s->level[var_of(l)];
6915
6916 l = a[1];
6917 v1 = literal_value(s, l);
6918 k1 = s->level[var_of(l)];
6919
6920 for (i=2; i<n; i++) {
6921 l = a[i];
6922 v = literal_value(s, l);
6923 k = s->level[var_of(l)];
6924 if (check_prefer(v, k, v0, k0) || check_prefer(v, k, v1, k1)) {
6925 goto error;
6926 }
6927 }
6928 return;
6929
6930 error:
6931 printf("Error: incorrect watched literals in new clause\n");
6932 printf("Clause: {");
6933 for (i=0; i<n; i++) {
6934 printf(" ");
6935 print_literal(stdout, a[i]);
6936 }
6937 printf(" }\n");
6938 print_lit_val_level(a[0], v0, k0);
6939 print_lit_val_level(a[1], v1, k1);
6940 print_lit_val_level(l, v, k);
6941 }
6942
check_lemma(smt_core_t * s,uint32_t n,literal_t * a)6943 static void check_lemma(smt_core_t *s, uint32_t n, literal_t *a) {
6944 uint32_t i;
6945 literal_t l;
6946
6947 for (i=0; i<n; i++) {
6948 l = a[i];
6949 if (l < 0 || l >= s->nlits) {
6950 printf("Error: invalid literal in lemma (l = %"PRId32")\n", l);
6951 fflush(stdout);
6952 }
6953 }
6954 }
6955
6956 #endif
6957
6958