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 * EGRAPH EXPLANATIONS *
21 ************************/
22
23 /*
24 * There are two phases to generating explanations:
25 * - when an equality (t1 == t2) is implied, an edge is added and an
26 * antecedent attached to that edge in the propagation queue
27 * - the antecedent encodes the reason for the implication.
28 * When explanations need to be communicated to the DPLL solver, the antecedents
29 * are visited and expanded into a vector of literals.
30 *
31 * Expansion is done in build_explanation_vector using a set of edges + a
32 * vector of literals:
33 * - to explain an edge i = (t1 == t2), we start with
34 * set = { i } , vector = empty vector
35 * - each processing step replaces an edge i in the set by other edges
36 * based on the explanation for i, or remove i from the set and add
37 * a literal to v
38 * - we do this until the set is empty: the resulting explanation is
39 * the vector
40 *
41 * Modification: the set is now a queue and all the edges in the queue
42 * are marked.
43 *
44 * It's important to ensure causality: the information stored as
45 * antecedent to edge i when an equality is implied must allow the
46 * same explanation to be reconstructed when edge i is expanded later.
47 * In particular, the expansion should not introduce any equalities
48 * asserted after i.
49 */
50
51
52 #include <stdint.h>
53 #include <stdbool.h>
54 #include <assert.h>
55
56 #include "solvers/egraph/composites.h"
57 #include "solvers/egraph/egraph.h"
58 #include "solvers/egraph/egraph_types.h"
59 #include "solvers/egraph/egraph_utils.h"
60 #include "solvers/egraph/theory_explanations.h"
61 #include "utils/bit_tricks.h"
62 #include "utils/int_vectors.h"
63 #include "utils/memalloc.h"
64
65
66 #if 0
67
68 #include <stdio.h>
69 #include <inttypes.h>
70
71 #include "solvers/cdcl/smt_core_printer.h"
72 #include "solvers/egraph/egraph_printer.h"
73
74 #endif
75
76
77 /**********************************
78 * CONSTRUCTION OF ANTECEDENTS *
79 *********************************/
80
81 /*
82 * Antecedent for (distinct t_1 ... t_n) == false
83 * The antecedent is EXPL_EQ(t_i, t_j) where t_i and t_j have label x
84 * - c = composite term (distinct t_1 ... t_n)
85 * - x = label (via which the simplification was detected)
86 * - k = index where the explanation must be stored in egraph->stack
87 */
gen_distinct_simpl_antecedent(egraph_t * egraph,composite_t * c,elabel_t x,int32_t k)88 void gen_distinct_simpl_antecedent(egraph_t *egraph, composite_t *c, elabel_t x, int32_t k) {
89 uint32_t i;
90 occ_t t1, t2;
91
92 assert(composite_kind(c) == COMPOSITE_DISTINCT);
93
94 i = 0;
95 do {
96 assert(i < composite_arity(c));
97 t1 = c->child[i];
98 i ++;
99 } while (egraph_label(egraph, t1) != x);
100
101 do {
102 assert(i < composite_arity(c));
103 t2 = c->child[i];
104 i ++;
105 } while (egraph_label(egraph, t2) != x);
106
107 egraph->stack.etag[k] = EXPL_EQ;
108 egraph->stack.edata[k].t[0] = t1;
109 egraph->stack.edata[k].t[1] = t2;
110 }
111
112
113 /*
114 * Antecedent for (distinct t_1 ... t_n) == (distinct u_1 ... u_n)
115 * - build a permutation v[1 ... n] of u_1 ... u_n such that t_i == u_{v[j]}
116 * - k = index where the explanation must be stored
117 */
gen_distinct_congruence_antecedent(egraph_t * egraph,composite_t * c1,composite_t * c2,int32_t k)118 void gen_distinct_congruence_antecedent(egraph_t *egraph, composite_t *c1, composite_t *c2, int32_t k) {
119 occ_t *aux, *ch;
120 uint32_t i, n;
121 int_hmap_t *imap;
122 int_hmap_pair_t *p;
123 elabel_t l;
124
125 assert(c1->tag == c2->tag && composite_kind(c1) == COMPOSITE_DISTINCT);
126
127 // store map [label(u_i) --> u_i] into imap
128 n = composite_arity(c1);
129 ch = c2->child;
130 imap = egraph_get_imap(egraph);
131 for (i=0; i<n; i++) {
132 l = egraph_label(egraph, ch[i]);
133 assert(l >= 0);
134 p = int_hmap_get(imap, l);
135 assert(p->val < 0); // otherwise (distinct u_1 ... u_n) == false
136 p->val = ch[i];
137 }
138
139 // for every t_i, find which u_j is mapped to label(t_i)
140 // store that u_j in aux[i]
141 aux = (occ_t *) arena_alloc(&egraph->arena, n * sizeof(occ_t));
142 ch = c1->child;
143 for (i=0; i<n; i++) {
144 l = egraph_label(egraph, ch[i]);
145 assert(l >= 0);
146 p = int_hmap_find(imap, l);
147 assert(p != NULL);
148 aux[i] = p->val;
149 }
150
151 egraph->stack.etag[k] = EXPL_DISTINCT_CONGRUENCE;
152 egraph->stack.edata[k].ptr = aux;
153
154 // cleanup
155 int_hmap_reset(imap);
156 }
157
158
159 /*
160 * Scan the path from t to its root
161 * - for every term x on this path, add the mapping [x -> t] or [x -> neg(t)]
162 * to imap (unless x is already mapped to some other term t')
163 */
map_path(egraph_t * egraph,int_hmap_t * imap,occ_t t)164 static void map_path(egraph_t *egraph, int_hmap_t *imap, occ_t t) {
165 eterm_t x;
166 occ_t u, v;
167 int_hmap_pair_t *p;
168 equeue_elem_t *eq;
169 int32_t *edge;
170 int32_t i;
171
172 edge = egraph->terms.edge;
173 eq = egraph->stack.eq;
174
175 t &= ~0x1; // clear sign bit: start with t positive
176 u = t;
177 for (;;) {
178 x = term_of_occ(u);
179
180 p = int_hmap_get(imap, x);
181 if (p->val >= 0) break;;
182 p->val = t;
183
184 i = edge[x];
185 if (i < 0) break;
186 v = edge_next_occ(eq + i, u);
187 // flip sign of t if u and v have opposite signs
188 t ^= (u ^ v) & 0x1;
189 u = v;
190 }
191 }
192
193 /*
194 * Add mapping [true_term -> false] to the imap (i.e. root(false) is mapped to false)
195 * if there's nothing mapped to true_term yet.
196 */
map_false_node(int_hmap_t * imap)197 static void map_false_node(int_hmap_t *imap) {
198 int_hmap_pair_t *p;
199
200 p = int_hmap_get(imap, term_of_occ(false_occ));
201 if (p->val < 0) {
202 p->val = false_occ;
203 }
204 }
205
206 /*
207 * Scan the path from t to its root until a term x is found in imap
208 * - return whatever is mapped to x with adjusted polarities
209 */
find_in_path(egraph_t * egraph,int_hmap_t * imap,occ_t t)210 static occ_t find_in_path(egraph_t *egraph, int_hmap_t *imap, occ_t t) {
211 int_hmap_pair_t *p;
212 equeue_elem_t *eq;
213 int32_t *edge;
214 int32_t i;
215 occ_t u, sgn;
216 eterm_t x;
217
218 edge = egraph->terms.edge;
219 eq = egraph->stack.eq;
220
221 sgn = polarity_of_occ(t);
222
223 for (;;) {
224 x = term_of_occ(t);
225
226 p = int_hmap_find(imap, x);
227 if (p != NULL) break;
228
229 i = edge[x];
230 assert(i >= 0); // i is not null_edge
231 u = edge_next_occ(eq + i, t);
232
233 // flip sign if t and u have opposite polarities
234 sgn ^= (u ^ t) & 0x1;
235 t = u;
236 }
237
238 // x is mapped to p->val (this encodes pos_occ(x) == p->val)
239 // we have t == pos_occ(x) ^ sign.
240
241 return p->val ^ sgn;
242 }
243
244
245
246 /*
247 * For every i in 0 ... n-1, choose u among { d[0] ... d[m-1] false }
248 * such that (c[i] == u) holds in the egraph. Store that term u into a[i].
249 */
half_or_congruence_antecedent(egraph_t * egraph,occ_t * c,uint32_t n,occ_t * d,uint32_t m,occ_t * a)250 static void half_or_congruence_antecedent(egraph_t *egraph, occ_t *c, uint32_t n, occ_t *d, uint32_t m, occ_t *a) {
251 int_hmap_t *imap;
252 uint32_t i;
253
254 imap = egraph_get_imap(egraph);
255 for (i=0; i<m; i++) {
256 map_path(egraph, imap, d[i]);
257 }
258
259 // if false node is not in imap then add it, mapped to itself
260 map_false_node(imap);
261
262 for (i=0; i<n; i++) {
263 a[i] = find_in_path(egraph, imap, c[i]);
264 }
265 int_hmap_reset(imap);
266 }
267
268
269
270 /*
271 * Antecedent for or-congruence (could be used for any AC operator)
272 * - c1 and c2 must be two composites of the form (or t_1 ... t_n) and (or u_1 ... u_m)
273 * - k = index where the explanation must be stored in egraph->stack
274 */
gen_or_congruence_antecedent(egraph_t * egraph,composite_t * c1,composite_t * c2,int32_t k)275 void gen_or_congruence_antecedent(egraph_t *egraph, composite_t *c1, composite_t *c2, int32_t k) {
276 occ_t *aux, *ch1, *ch2;
277 uint32_t n1, n2;
278
279 assert(composite_kind(c1) == COMPOSITE_OR && composite_kind(c2) == COMPOSITE_OR);
280
281 n1 = composite_arity(c1);
282 n2 = composite_arity(c2);
283 aux = (occ_t *) arena_alloc(&egraph->arena, (n1 + n2) * sizeof(occ_t));
284 ch1 = c1->child;
285 ch2 = c2->child;
286
287 half_or_congruence_antecedent(egraph, ch1, n1, ch2, n2, aux);
288 half_or_congruence_antecedent(egraph, ch2, n2, ch1, n1, aux + n1);
289
290 egraph->stack.etag[k] = EXPL_OR_CONGRUENCE;
291 egraph->stack.edata[k].ptr = aux;
292 }
293
294
295
296
297
298 /************************************
299 * EXPANSION INTO LITERAL VECTORS *
300 ***********************************/
301
302 /*
303 * Add edge i to the explanation queue if it's not marked and mark it.
304 */
enqueue_edge(ivector_t * eq,byte_t * mark,int32_t i)305 static inline void enqueue_edge(ivector_t *eq, byte_t *mark, int32_t i) {
306 if (!tst_bit(mark, i)) {
307 set_bit(mark, i);
308 ivector_push(eq, i);
309 }
310 }
311
312 /*
313 * Mark all unmarked edges on the path from t1 to t and add them to the explanation queue.
314 */
mark_path(egraph_t * egraph,eterm_t t1,eterm_t t)315 static void mark_path(egraph_t *egraph, eterm_t t1, eterm_t t) {
316 equeue_elem_t *eq;
317 int32_t *edge;
318 byte_t *mark;
319 ivector_t *q;
320 int32_t i;
321
322 edge = egraph->terms.edge;
323 eq = egraph->stack.eq;
324 mark = egraph->stack.mark;
325 q = &egraph->expl_queue;
326
327 while (t1 != t) {
328 i = edge[t1];
329 assert(i >= 0);
330 enqueue_edge(q, mark, i);
331 t1 = edge_next(eq + i, t1);
332 }
333 }
334
335 /*
336 * Find common ancestor to t1 and t2 in the explanation tree
337 * - both must be in the same class
338 */
common_ancestor(egraph_t * egraph,eterm_t t1,eterm_t t2)339 static eterm_t common_ancestor(egraph_t *egraph, eterm_t t1, eterm_t t2) {
340 equeue_elem_t *eq;
341 int32_t *edge;
342 byte_t *mark;
343 int32_t i;
344 eterm_t t;
345
346 assert(egraph_term_class(egraph, t1) == egraph_term_class(egraph, t2));
347
348 edge = egraph->terms.edge;
349 mark = egraph->terms.mark;
350 eq = egraph->stack.eq;
351
352 // mark all nodes on the path from t1 to its root
353 t = t1;
354 for (;;) {
355 set_bit(mark, t);
356 i = edge[t];
357 if (i == null_edge) break;
358 t = edge_next(eq + i, t);
359 }
360
361 // find first marked ancestor of t2
362 while (! tst_bit(mark, t2)) {
363 i = edge[t2];
364 assert(i >= 0);
365 t2 = edge_next(eq + i, t2);
366 }
367
368 // clear all marks
369 for (;;) {
370 clr_bit(mark, t1);
371 i = edge[t1];
372 if (i == null_edge) break;
373 t1 = edge_next(eq + i, t1);
374 }
375
376 return t2;
377 }
378
379
380 /*
381 * SHORT CUTS FOR EQUALITY EXPLANATION
382 */
383
384 /*
385 * Rather than processing the egraph merge trees to construct explanation.
386 * we can look for short cuts. A short cut for explaining (t1 == t2)
387 * is a literal l such that
388 * 1) l is equivalent to (t1 == t2)
389 * 2) l is true in the smt_core
390 * 3) l does not cause a circularity in the explanation
391 *
392 * To check condition 3: we keep track of the edge index that triggers
393 * a theory propagation from the egraph to the core: that's an edge
394 * that causes merging of a class c with the Boolean constant class.
395 * This causes all terms in c's class to be mapped to true or false,
396 * and corresponding literals to be propagated in the smt_core.
397 * If l is such a literal, then the antecedent for l in the core
398 * stores the index k of the edge that triggered the propagation.
399 *
400 * When building an explanation for an egraph conflict, the index k
401 * does not matter. When building an explanation for something else
402 * (i.e., an equality (u1 == u2), then we can take l as a short cut
403 * if i < k.
404 */
405
406 /*
407 * Literal equivalent to a Boolean term occurrence x.
408 *
409 * NOTE: Some Boolean terms don't have a theory variable. They come
410 * from axioms of the form (not (eq t1 t2))
411 * (cf. egraph_assert_diseq_axiom)
412 */
literal_for_eterm(egraph_t * egraph,occ_t x)413 static literal_t literal_for_eterm(egraph_t *egraph, occ_t x) {
414 eterm_t tx;
415 bvar_t v;
416 literal_t l;
417
418 tx = term_of_occ(x);
419 assert(egraph_term_is_bool(egraph, tx));
420 v = egraph_term_base_thvar(egraph, tx);
421 l = null_literal;
422 if (v != null_thvar) {
423 l = mk_signed_lit(v, is_pos_occ(x));
424 }
425
426 return l;
427 }
428
429 /*
430 * Search for a literal equivalent to (x == y)
431 * - return a negative integer if no literal is found:
432 * either null_literal (i.e., -1) or -2 (i.e., null_literal ^ 1)
433 */
literal_for_eq(egraph_t * egraph,occ_t x,occ_t y)434 static literal_t literal_for_eq(egraph_t *egraph, occ_t x, occ_t y) {
435 if (term_of_occ(x) == true_eterm) {
436 /*
437 * x is either true_occ or false_occ
438 * - if x is true_occ, we return the literal for y
439 * - if x is false_occ, we return the opposite of the literal for y
440 * we do this by flipping the low order bit if x is false, that is if
441 * polarity of x is 1.
442 */
443 return literal_for_eterm(egraph, y) ^ polarity_of_occ(x);
444 }
445
446 if (term_of_occ(y) == true_eterm) {
447 // y is either true_occ or false_occ
448 return literal_for_eterm(egraph, x) ^ polarity_of_occ(y);
449 }
450
451 // otherwise: search for (eq x y)
452 return egraph_find_eq(egraph, x, y);
453 }
454
455
456
457 /*
458 * Explanation for (x == y) or (x == (not y)) when x and y are in the same class.
459 * - if short_cuts are enabled, search for a literal l that's equivalent to (x == y)
460 * and add it to vector v
461 * - it short_cuts are disabled, or no l is found, use symmetry/transitivity:
462 * find a path between x and y, mark all unmarked edges on that path
463 */
explain_eq(egraph_t * egraph,occ_t x,occ_t y,ivector_t * v)464 static void explain_eq(egraph_t *egraph, occ_t x, occ_t y, ivector_t *v) {
465 eterm_t tx, ty, w;
466 literal_t l;
467 antecedent_t a;
468 int32_t id;
469
470 assert(egraph_same_class(egraph, x, y));
471
472 tx = term_of_occ(x);
473 ty = term_of_occ(y);
474
475 if (tx == ty) return;
476
477 if (egraph->short_cuts) {
478 assert(v != NULL);
479
480 l = literal_for_eq(egraph, x, y);
481 if (l >= 0) {
482 if (egraph_opposite_occ(egraph, x, y)) {
483 l = not(l);
484 }
485
486 if (l == true_literal) {
487 #if 0
488 printf("---> possible short cut: ");
489 print_literal(stdout, l);
490 printf("\n");
491 #endif
492 return;
493 }
494
495 if (literal_value(egraph->core, l) == VAL_TRUE) {
496 a = get_bvar_antecedent(egraph->core, var_of(l));
497 if (antecedent_tag(a) == generic_tag) {
498 // i.e., l was propagated by the Egraph
499 id = i32_of_expl(generic_antecedent(a));
500 if (id < egraph->top_id) {
501 #if 0
502 printf("---> short cut: ");
503 print_literal(stdout, l);
504 printf(" := ");
505 print_egraph_atom_of_literal(stdout, egraph, l);
506 printf("\n");
507 #endif
508 ivector_push(v, l);
509 return;
510 }
511 }
512 }
513 }
514 }
515
516 w = common_ancestor(egraph, tx, ty);
517 mark_path(egraph, tx, w);
518 mark_path(egraph, ty, w);
519 }
520
521
522
523 /*
524 * SUPPORT FOR CAUSAL EXPLANATIONS
525 */
526
527 /*
528 * Check whether all edges on the path from t1 to t precede k
529 * (i.e., whether t1 == t was true when edge k was added).
530 * - t must be an ancestor of t1
531 */
path_precedes_edge(egraph_t * egraph,eterm_t t1,eterm_t t,int32_t k)532 static bool path_precedes_edge(egraph_t *egraph, eterm_t t1, eterm_t t, int32_t k) {
533 equeue_elem_t *eq;
534 int32_t *edge;
535 int32_t i;
536
537 edge = egraph->terms.edge;
538 eq = egraph->stack.eq;
539
540 while (t1 != t) {
541 i = edge[t1];
542 assert(i >= 0);
543 if (i >= k) return false;
544 t1 = edge_next(eq + i, t1);
545 }
546
547 return true;
548 }
549
550
551 /*
552 * Check whether (x == y) or (x == (not y)) was true when edge k was added
553 * - x and y must be in the same class
554 */
causally_equal(egraph_t * egraph,occ_t x,occ_t y,int32_t k)555 static bool causally_equal(egraph_t *egraph, occ_t x, occ_t y, int32_t k) {
556 eterm_t tx, ty, w;
557
558 assert(egraph_same_class(egraph, x, y));
559
560 tx = term_of_occ(x);
561 ty = term_of_occ(y);
562
563 if (tx == ty) return true;
564
565 w = common_ancestor(egraph, tx, ty);
566 return path_precedes_edge(egraph, tx, w, k) && path_precedes_edge(egraph, ty, w, k);
567 }
568
569
570
571 /*
572 * DISEQUALITY EXPLANATIONS
573 */
574
575 /*
576 * Check whether term t is constant
577 */
eterm_is_constant(egraph_t * egraph,eterm_t t)578 static bool eterm_is_constant(egraph_t *egraph, eterm_t t) {
579 thvar_t x;
580 etype_t tau;
581
582 if (constant_body(egraph_term_body(egraph, t))) {
583 return true;
584 }
585
586 x = egraph_term_base_thvar(egraph, t);
587 if (x != null_thvar) {
588 tau = egraph_term_type(egraph, t);
589 switch (tau) {
590 case ETYPE_INT:
591 case ETYPE_REAL:
592 case ETYPE_BV:
593 return egraph->eg[tau]->is_constant(egraph->th[tau], x);
594
595 default:
596 break;
597 }
598 }
599
600 return false;
601 }
602
603
604
605 /*
606 * Find a constant t in the class of x then return t+
607 * Warning: make sure there's a constant in the class before calling this.
608 */
constant_in_class(egraph_t * egraph,occ_t x)609 static occ_t constant_in_class(egraph_t *egraph, occ_t x) {
610 eterm_t t;
611
612 t = term_of_occ(x);
613 while (! eterm_is_constant(egraph, t)) {
614 // while (! constant_body(egraph_term_body(egraph, t))) {
615 t = term_of_occ(egraph->terms.next[t]);
616 assert(t != term_of_occ(x));
617 }
618
619 return pos_occ(t);
620 }
621
622 /*
623 * Explanation for (x != y) via bit 0 of dmasks:
624 * - find two constants a and b such that x == a and y == b
625 */
explain_diseq_via_constants(egraph_t * egraph,occ_t x,occ_t y,ivector_t * v)626 static void explain_diseq_via_constants(egraph_t *egraph, occ_t x, occ_t y, ivector_t *v) {
627 explain_eq(egraph, x, constant_in_class(egraph, x), v);
628 explain_eq(egraph, y, constant_in_class(egraph, y), v);
629 }
630
631
632 /*
633 * Explanation for (x != y) from (distinct u_1 ... u_n)
634 * - we must have (distinct u_1 ... u_n) == true, x == u_i, y == u_j for i/=j
635 * - the explanation is built using edges that precede k
636 */
explain_diseq_via_distinct(egraph_t * egraph,occ_t x,occ_t y,composite_t * d,int32_t k,ivector_t * v)637 static void explain_diseq_via_distinct(egraph_t *egraph, occ_t x, occ_t y, composite_t *d, int32_t k, ivector_t *v) {
638 class_t cx, cy;
639 occ_t t, tx, ty;
640 uint32_t i;
641
642 assert(composite_kind(d) == COMPOSITE_DISTINCT);
643
644 t = pos_occ(d->id);
645 assert(egraph_label(egraph, t) == true_label);
646 explain_eq(egraph, t, true_occ, v);
647
648 cx = egraph_class(egraph, x);
649 cy = egraph_class(egraph, y);
650 assert(cx != cy);
651
652 // find terms tx of class cx and ty of class cy in d
653 i = 0;
654 tx = null_occurrence;
655 ty = null_occurrence;
656 for (;;) {
657 assert(i < composite_arity(d));
658 t = d->child[i];
659
660 if (egraph_class(egraph, t) == cx && causally_equal(egraph, t, x, k)) {
661 assert(tx == null_occurrence);
662 tx = t;
663 if (ty != null_occurrence) break;
664
665 } else if (egraph_class(egraph, t) == cy && causally_equal(egraph, t, y, k)) {
666 assert(ty == null_occurrence);
667 ty = t;
668 if (tx != null_occurrence) break;
669 }
670
671 i ++;
672 }
673
674 explain_eq(egraph, x, tx, v);
675 explain_eq(egraph, y, ty, v);
676 }
677
678
679
680 /*
681 * Explanation for (x != y) via the dmasks
682 * - i = index of the distinct term that implied (x != y)
683 * - i must be between 1 and 31
684 * - k = index of the edge that uses (x != y) as antecedent
685 */
explain_diseq_via_dmasks(egraph_t * egraph,occ_t x,occ_t y,uint32_t i,int32_t k,ivector_t * v)686 static void explain_diseq_via_dmasks(egraph_t *egraph, occ_t x, occ_t y, uint32_t i, int32_t k, ivector_t *v) {
687 composite_t *dpred;
688
689 assert(1 <= i && i < egraph->dtable.npreds);
690
691 dpred = egraph->dtable.distinct[i];
692 assert(dpred != NULL && composite_kind(dpred) == COMPOSITE_DISTINCT);
693
694 explain_diseq_via_distinct(egraph, x, y, dpred, k, v);
695 }
696
697
698
699
700 /*
701 * SIMPLIFICATION AND CONGRUENCE
702 */
703
704 /*
705 * Explanation for (or t1 ... tn) == false
706 * - t_i == false for all i
707 */
explain_simp_or_false(egraph_t * egraph,composite_t * c,ivector_t * v)708 static void explain_simp_or_false(egraph_t *egraph, composite_t *c, ivector_t *v) {
709 uint32_t i, m;
710
711 assert(composite_kind(c) == COMPOSITE_OR);
712 m = composite_arity(c);
713 for (i=0; i<m; i++) {
714 explain_eq(egraph, c->child[i], false_occ, v);
715 }
716 }
717
718
719 /*
720 * Explanation for (or t1 ... tn) == u
721 * - either t_i == false or t_i == v for all i
722 */
explain_simp_or(egraph_t * egraph,composite_t * c,occ_t u,ivector_t * v)723 static void explain_simp_or(egraph_t *egraph, composite_t *c, occ_t u, ivector_t *v) {
724 uint32_t i, m;
725 occ_t t;
726
727 assert(composite_kind(c) == COMPOSITE_OR);
728
729 m = composite_arity(c);
730 for (i=0; i<m; i++) {
731 t = c->child[i];
732 if (egraph_occ_is_false(egraph, t)) {
733 explain_eq(egraph, t, false_occ, v);
734 } else {
735 explain_eq(egraph, t, u, v);
736 }
737 }
738 }
739
740
741
742 /*
743 * Explanation for "c1 and c2 are congruent" when c1 and c2 are apply, update, or tuple terms
744 */
explain_congruence(egraph_t * egraph,composite_t * c1,composite_t * c2,ivector_t * v)745 static void explain_congruence(egraph_t *egraph, composite_t *c1, composite_t *c2, ivector_t *v) {
746 uint32_t i, m;
747
748 assert(c1->tag == c2->tag);
749
750 m = composite_arity(c1);
751 for (i=0; i<m; i++) {
752 explain_eq(egraph, c1->child[i], c2->child[i], v);
753 }
754 }
755
756 /*
757 * (eq t1 t2) congruent to (eq u1 u2): two variants
758 */
explain_eq_congruence1(egraph_t * egraph,composite_t * c1,composite_t * c2,ivector_t * v)759 static void explain_eq_congruence1(egraph_t *egraph, composite_t *c1, composite_t *c2, ivector_t *v) {
760 explain_eq(egraph, c1->child[0], c2->child[0], v);
761 explain_eq(egraph, c1->child[1], c2->child[1], v);
762 }
763
explain_eq_congruence2(egraph_t * egraph,composite_t * c1,composite_t * c2,ivector_t * v)764 static void explain_eq_congruence2(egraph_t *egraph, composite_t *c1, composite_t *c2, ivector_t *v) {
765 explain_eq(egraph, c1->child[0], c2->child[1], v);
766 explain_eq(egraph, c1->child[1], c2->child[0], v);
767 }
768
769
770 /*
771 * (ite t1 t2 t3) congruent to (ite u1 u2 u3): two variants
772 */
explain_ite_congruence1(egraph_t * egraph,composite_t * c1,composite_t * c2,ivector_t * v)773 static void explain_ite_congruence1(egraph_t *egraph, composite_t *c1, composite_t *c2, ivector_t *v) {
774 explain_eq(egraph, c1->child[0], c2->child[0], v);
775 explain_eq(egraph, c1->child[1], c2->child[1], v);
776 explain_eq(egraph, c1->child[2], c2->child[2], v);
777 }
778
explain_ite_congruence2(egraph_t * egraph,composite_t * c1,composite_t * c2,ivector_t * v)779 static void explain_ite_congruence2(egraph_t *egraph, composite_t *c1, composite_t *c2, ivector_t *v) {
780 // the first call to explain_eq is for c1->child[0] == (not c2->child[0])
781 explain_eq(egraph, c1->child[0], c2->child[0], v);
782 explain_eq(egraph, c1->child[1], c2->child[2], v);
783 explain_eq(egraph, c1->child[2], c2->child[1], v);
784 }
785
786
787 /*
788 * Explanation for "c1 and c2 are congruent" when
789 * c1 is (or t_1 ... t_n)
790 * c2 is (or u_1 ... u_m)
791 * p is an array of n+m term occurrences
792 * the explanation if the conjunction
793 * (t_1 == p[0] and ... and t_n == p[n-1]) and (u_1 == p[n] and ... and u_m == p[n+m-1])
794 */
explain_or_congruence(egraph_t * egraph,composite_t * c1,composite_t * c2,occ_t * p,ivector_t * v)795 static void explain_or_congruence(egraph_t *egraph, composite_t *c1, composite_t *c2, occ_t *p, ivector_t *v) {
796 uint32_t i, k;
797
798 k = composite_arity(c1);
799 for (i=0; i<k; i++) {
800 explain_eq(egraph, c1->child[i], *p, v);
801 p ++;
802 }
803
804 k = composite_arity(c2);
805 for (i=0; i<k; i++) {
806 explain_eq(egraph, c2->child[i], *p, v);
807 p ++;
808 }
809 }
810
811 /*
812 * Explanation for (distinct t_1 ... t_n) == (distinct u_1 ... u_n)
813 * p is a permutation of u_1 ... u_n
814 * the explanation is the conjunction
815 * (t_1 == p[0] ... t_n == p[n-1])
816 */
explain_distinct_congruence(egraph_t * egraph,composite_t * c1,composite_t * c2,occ_t * p,ivector_t * v)817 static void explain_distinct_congruence(egraph_t *egraph, composite_t *c1, composite_t *c2, occ_t *p, ivector_t *v) {
818 uint32_t i, k;
819
820 k = composite_arity(c1);
821 for (i=0; i<k; i++) {
822 explain_eq(egraph, c1->child[i], p[i], v);
823 }
824 }
825
826
827
828 /*
829 * Convert the explanation tag for a theory equality to the corresponding theory type
830 */
etag2theory(expl_tag_t id)831 static inline etype_t etag2theory(expl_tag_t id) {
832 int32_t tau;
833
834 assert(EXPL_ARITH_PROPAGATION <= id && id <= EXPL_FUN_PROPAGATION);
835 tau = ETYPE_REAL + id - EXPL_ARITH_PROPAGATION;
836 assert(ETYPE_REAL <= tau && tau <= ETYPE_FUNCTION);
837 return (etype_t) tau;
838 }
839
840
841 /*
842 * Explanation for equality (t1 == t2) propagated from a theory solver
843 * - id = one of EXPL_ARITH_PROPAGATION, EXPL_BV_PROPAGATION, EXPL_FUN_PROPAGATION
844 * - expl = whatever the solver gave as explanation when it called egraph_propagate_equality
845 * - v = vector of literals (partial explanation under construction)
846 */
explain_theory_equality(egraph_t * egraph,expl_tag_t id,eterm_t t1,eterm_t t2,void * expl,ivector_t * v)847 static void explain_theory_equality(egraph_t *egraph, expl_tag_t id, eterm_t t1, eterm_t t2,
848 void *expl, ivector_t *v) {
849 th_explanation_t *e;
850 etype_t tau;
851 thvar_t x1, x2;
852 uint32_t i, n;
853 literal_t *atoms;
854 th_eq_t *eqs;
855 diseq_pre_expl_t *diseqs;
856 composite_t *cmp;
857 occ_t t;
858
859 e = &egraph->th_expl;
860 tau = etag2theory(id);
861 x1 = egraph_term_base_thvar(egraph, t1);
862 x2 = egraph_term_base_thvar(egraph, t2);
863
864 assert(x1 != null_thvar && x2 != null_thvar);
865
866 // get explanation from the satellite solver
867 reset_th_explanation(e);
868 egraph->eg[tau]->expand_th_explanation(egraph->th[tau], x1, x2, expl, e);
869
870 /*
871 * e->atoms = list of literals (attached to theory specific atoms)
872 */
873 atoms = e->atoms;
874 if (atoms != NULL) {
875 n = get_av_size(atoms);
876 for (i=0; i<n; i++) {
877 ivector_push(v, atoms[i]);
878 }
879 }
880
881 /*
882 * e->eqs = list of equalities
883 */
884 eqs = e->eqs;
885 if (eqs != NULL) {
886 n = get_eqv_size(eqs);
887 for (i=0; i<n; i++) {
888 explain_eq(egraph, pos_occ(eqs[i].lhs), pos_occ(eqs[i].rhs), v);
889 }
890 }
891
892 /*
893 * e->diseqs = list of disequalities + hint
894 */
895 diseqs = e->diseqs;
896 if (diseqs != NULL) {
897 n = get_diseqv_size(diseqs);
898 for (i=0; i<n; i++) {
899 cmp = diseqs[i].hint;
900 t = pos_occ(cmp->id);
901 if (composite_kind(cmp) == COMPOSITE_EQ) {
902 assert(egraph_label(egraph, t) == false_label);
903 explain_eq(egraph, t, false_occ, v);
904 } else {
905 assert(composite_kind(cmp) == COMPOSITE_DISTINCT && egraph_label(egraph, t) == true_label);
906 explain_eq(egraph, t, true_occ, v);
907 }
908 explain_eq(egraph, pos_occ(diseqs[i].t1), pos_occ(diseqs[i].u1), v);
909 explain_eq(egraph, pos_occ(diseqs[i].t2), pos_occ(diseqs[i].u2), v);
910 }
911 }
912 }
913
914
915
916
917
918
919 /*
920 * EXPLANATION VECTOR
921 */
922
923 /*
924 * Expand the marked edges into a vector of literals
925 * - v = result vector: literals are added to it (v is not reset)
926 */
build_explanation_vector(egraph_t * egraph,ivector_t * v)927 static void build_explanation_vector(egraph_t *egraph, ivector_t *v) {
928 equeue_elem_t *eq;
929 byte_t *mark;
930 ivector_t *queue;
931 unsigned char *etag;
932 expl_data_t *edata;
933 composite_t **body;
934 eterm_t t1, t2;
935 uint32_t k;
936 int32_t i;
937
938 eq = egraph->stack.eq;
939 mark = egraph->stack.mark;
940 etag = egraph->stack.etag;
941 edata = egraph->stack.edata;
942 body = egraph->terms.body;
943 queue = &egraph->expl_queue;
944
945 for (k = 0; k < queue->size; k++) {
946 i = queue->data[k];
947 assert(i >= 0 && tst_bit(mark, i));
948 switch (etag[i]) {
949 case EXPL_AXIOM:
950 break;
951
952 case EXPL_ASSERT:
953 ivector_push(v, edata[i].lit);
954 break;
955
956 case EXPL_EQ:
957 explain_eq(egraph, edata[i].t[0], edata[i].t[1], v);
958 break;
959
960 case EXPL_DISTINCT0:
961 explain_diseq_via_constants(egraph, edata[i].t[0], edata[i].t[1], v);
962 break;
963
964 case EXPL_DISTINCT1:
965 case EXPL_DISTINCT2:
966 case EXPL_DISTINCT3:
967 case EXPL_DISTINCT4:
968 case EXPL_DISTINCT5:
969 case EXPL_DISTINCT6:
970 case EXPL_DISTINCT7:
971 case EXPL_DISTINCT8:
972 case EXPL_DISTINCT9:
973 case EXPL_DISTINCT10:
974 case EXPL_DISTINCT11:
975 case EXPL_DISTINCT12:
976 case EXPL_DISTINCT13:
977 case EXPL_DISTINCT14:
978 case EXPL_DISTINCT15:
979 case EXPL_DISTINCT16:
980 case EXPL_DISTINCT17:
981 case EXPL_DISTINCT18:
982 case EXPL_DISTINCT19:
983 case EXPL_DISTINCT20:
984 case EXPL_DISTINCT21:
985 case EXPL_DISTINCT22:
986 case EXPL_DISTINCT23:
987 case EXPL_DISTINCT24:
988 case EXPL_DISTINCT25:
989 case EXPL_DISTINCT26:
990 case EXPL_DISTINCT27:
991 case EXPL_DISTINCT28:
992 case EXPL_DISTINCT29:
993 case EXPL_DISTINCT30:
994 case EXPL_DISTINCT31:
995 explain_diseq_via_dmasks(egraph, edata[i].t[0], edata[i].t[1], (uint32_t) (etag[i] - EXPL_DISTINCT0), i, v);
996 break;
997
998 case EXPL_SIMP_OR:
999 // eq[i].lhs = (or ...), rhs == false or term occurrence
1000 t1 = term_of_occ(eq[i].lhs);
1001 assert(composite_body(body[t1]));
1002 if (eq[i].rhs == false_occ) {
1003 explain_simp_or_false(egraph, body[t1], v);
1004 } else {
1005 explain_simp_or(egraph, body[t1], eq[i].rhs, v);
1006 }
1007 break;
1008
1009 case EXPL_BASIC_CONGRUENCE:
1010 t1 = term_of_occ(eq[i].lhs);
1011 t2 = term_of_occ(eq[i].rhs);
1012 explain_congruence(egraph, body[t1], body[t2], v);
1013 break;
1014
1015 case EXPL_EQ_CONGRUENCE1:
1016 t1 = term_of_occ(eq[i].lhs);
1017 t2 = term_of_occ(eq[i].rhs);
1018 explain_eq_congruence1(egraph, body[t1], body[t2], v);
1019 break;
1020
1021 case EXPL_EQ_CONGRUENCE2:
1022 t1 = term_of_occ(eq[i].lhs);
1023 t2 = term_of_occ(eq[i].rhs);
1024 explain_eq_congruence2(egraph, body[t1], body[t2], v);
1025 break;
1026
1027 case EXPL_ITE_CONGRUENCE1:
1028 t1 = term_of_occ(eq[i].lhs);
1029 t2 = term_of_occ(eq[i].rhs);
1030 explain_ite_congruence1(egraph, body[t1], body[t2], v);
1031 break;
1032
1033 case EXPL_ITE_CONGRUENCE2:
1034 t1 = term_of_occ(eq[i].lhs);
1035 t2 = term_of_occ(eq[i].rhs);
1036 explain_ite_congruence2(egraph, body[t1], body[t2], v);
1037 break;
1038
1039 case EXPL_OR_CONGRUENCE:
1040 t1 = term_of_occ(eq[i].lhs);
1041 t2 = term_of_occ(eq[i].rhs);
1042 explain_or_congruence(egraph, body[t1], body[t2], edata[i].ptr, v);
1043 break;
1044
1045 case EXPL_DISTINCT_CONGRUENCE:
1046 t1 = term_of_occ(eq[i].lhs);
1047 t2 = term_of_occ(eq[i].rhs);
1048 explain_distinct_congruence(egraph, body[t1], body[t2], edata[i].ptr, v);
1049 break;
1050
1051 case EXPL_ARITH_PROPAGATION:
1052 case EXPL_BV_PROPAGATION:
1053 case EXPL_FUN_PROPAGATION:
1054 t1 = term_of_occ(eq[i].lhs);
1055 t2 = term_of_occ(eq[i].rhs);
1056 explain_theory_equality(egraph, etag[i], t1, t2, edata[i].ptr, v);
1057 break;
1058
1059 case EXPL_RECONCILE:
1060 assert(false);
1061 break;
1062 }
1063 }
1064
1065 // clear all the marks
1066 for (k=0; k<queue->size; k++) {
1067 i = queue->data[k];
1068 assert(i >= 0 && tst_bit(mark, i));
1069 clr_bit(mark, i);
1070 }
1071 ivector_reset(queue);
1072
1073 // remove duplicates
1074 ivector_remove_duplicates(v);
1075 }
1076
1077
1078
1079
1080 /*
1081 * Build explanation for (t1 == t2): requires class[t1] == class[t2]
1082 * - id = edge index: all edges used in building the explanation must have index < id
1083 */
egraph_explain_equality(egraph_t * egraph,occ_t t1,occ_t t2,int32_t id,ivector_t * v)1084 void egraph_explain_equality(egraph_t *egraph, occ_t t1, occ_t t2, int32_t id, ivector_t *v) {
1085 assert(egraph_equal_occ(egraph, t1, t2));
1086 assert(egraph->expl_queue.size == 0);
1087 egraph->top_id = id;
1088 explain_eq(egraph, t1, t2, v);
1089 build_explanation_vector(egraph, v);
1090 }
1091
1092
1093
1094 /*
1095 * Explanation for (t1 != t2) either via dmasks or via an atom (eq u v) == false
1096 * with t1 == u and t2 == v.
1097 */
explain_diseq(egraph_t * egraph,occ_t t1,occ_t t2,ivector_t * v)1098 static void explain_diseq(egraph_t *egraph, occ_t t1, occ_t t2, ivector_t *v) {
1099 composite_t *eq;
1100 class_t c1, c2;
1101 occ_t aux;
1102 uint32_t msk;
1103 int32_t k;
1104
1105 c1 = egraph_class(egraph, t1);
1106 c2 = egraph_class(egraph, t2);
1107
1108 assert(c1 != c2);
1109
1110 msk = egraph->classes.dmask[c1] & egraph->classes.dmask[c2];
1111 if ((msk & 1) != 0) {
1112 explain_diseq_via_constants(egraph, t1, t2, v);
1113 return;
1114 } else if (msk != 0){
1115 assert(1 <= ctz(msk) && ctz(msk) < egraph->dtable.npreds);
1116 k = egraph->stack.top;
1117 explain_diseq_via_dmasks(egraph, t1, t2, ctz(msk), k, v);
1118 return;
1119 }
1120
1121 // search for a composite (eq u v) such that (eq u v) == false
1122 // u == t1, and v == t2
1123 eq = congruence_table_find_eq(&egraph->ctable, t1, t2, egraph->terms.label);
1124
1125 if (eq != NULL_COMPOSITE && egraph_occ_is_false(egraph, pos_occ(eq->id))) {
1126
1127 explain_eq(egraph, pos_occ(eq->id), false_occ, v);
1128
1129 if (c1 != egraph_class(egraph, eq->child[0])) {
1130 assert(c2 == egraph_class(egraph, eq->child[0]));
1131 aux = t1; t1 = t2; t2 = aux;
1132 }
1133
1134 explain_eq(egraph, t1, eq->child[0], v);
1135 explain_eq(egraph, t2, eq->child[1], v);
1136
1137 } else {
1138 // they don't look disequal
1139 assert(false);
1140 abort();
1141 }
1142 }
1143
1144
1145
1146
1147
1148
1149 /*
1150 * Disequality pre-explanation objects. These must be used if the
1151 * egraph propagates (x1 != x2) to a satellite solver and the solver
1152 * uses this disequality as antecedent in further propagation. The
1153 * explanation for (x1 != x2) can be constructed in two steps:
1154 *
1155 * 1) eager step: call egraph_store_diseq_pre_expl
1156 * This must be done when (x1 != x2) is received from the egraph
1157 * to store sufficnet data into a diseq_pre_expl_t object.
1158 *
1159 * 2) lazy step: expand the pre-expl data into a set of literals.
1160 * Can be done lazily, only when the explanation is needed.
1161 */
1162
1163
1164 /*
1165 * Auxiliary function: find a child of cmp that's equal to t
1166 * in the egraph. Return null_occurrence if there's none.
1167 */
find_equal_child(egraph_t * egraph,composite_t * cmp,occ_t t)1168 static occ_t find_equal_child(egraph_t *egraph, composite_t *cmp, occ_t t) {
1169 uint32_t i, n;
1170 occ_t x;
1171 elabel_t l;
1172
1173 n = composite_arity(cmp);
1174 l = egraph_label(egraph, t);
1175 for (i=0; i<n; i++) {
1176 x = cmp->child[i];
1177 if (egraph_label(egraph, x) == l) {
1178 return x;
1179 }
1180 }
1181
1182 return null_occurrence;
1183 }
1184
1185
1186 /*
1187 * Eager step: build a pre-explanation for (x1 != x2)
1188 * - t1 must be the egraph term attached to theory variable x1
1189 * - t2 must be the egraph term attached to theory variable x2
1190 * - hint must be the composite passed by the egraph in the call
1191 * to assert_disequality or assert_distinct
1192 * - p: pointer to a pre-explanation structure to fill in
1193 */
egraph_store_diseq_pre_expl(egraph_t * egraph,eterm_t t1,eterm_t t2,composite_t * hint,diseq_pre_expl_t * p)1194 void egraph_store_diseq_pre_expl(egraph_t *egraph, eterm_t t1, eterm_t t2, composite_t *hint, diseq_pre_expl_t *p) {
1195 occ_t u;
1196
1197 p->hint = hint;
1198 p->t1 = t1;
1199 p->t2 = t2;
1200
1201 u = find_equal_child(egraph, hint, pos_occ(t1));
1202 assert(u != null_occurrence && is_pos_occ(u) && egraph_equal_occ(egraph, pos_occ(t1), u));
1203 p->u1 = term_of_occ(u);
1204
1205 u = find_equal_child(egraph, hint, pos_occ(t2));
1206 assert(u != null_occurrence && is_pos_occ(u) && egraph_equal_occ(egraph, pos_occ(t2), u));
1207 p->u2 = term_of_occ(u);
1208
1209 assert(p->u1 != p->u2);
1210 }
1211
1212
1213
1214 /*
1215 * Lazy step: expand a pre-explanation into an array of literals
1216 * - p: pre-explanation structured set by the previous function
1217 * - v: vector where literals will be added.
1218 */
egraph_expand_diseq_pre_expl(egraph_t * egraph,diseq_pre_expl_t * p,ivector_t * v)1219 void egraph_expand_diseq_pre_expl(egraph_t *egraph, diseq_pre_expl_t *p, ivector_t *v) {
1220 composite_t *hint;
1221 occ_t t;
1222
1223 assert(egraph->expl_queue.size == 0);
1224 hint = p->hint;
1225 t = pos_occ(hint->id);
1226 if (composite_kind(hint) == COMPOSITE_EQ) {
1227 assert(egraph_label(egraph, t) == false_label);
1228 explain_eq(egraph, t, false_occ, v);
1229 } else {
1230 assert(composite_kind(hint) == COMPOSITE_DISTINCT && egraph_label(egraph, t) == true_label);
1231 explain_eq(egraph, t, true_occ, v);
1232 }
1233
1234 explain_eq(egraph, pos_occ(p->t1), pos_occ(p->u1), v);
1235 explain_eq(egraph, pos_occ(p->t2), pos_occ(p->u2), v);
1236
1237 build_explanation_vector(egraph, v);
1238 }
1239
1240
1241
1242 /*
1243 * Explanation for (distinct t_1 ... t_n) == true,
1244 * when dmask[class[t1]] & ... & dmask[class[t_n]]) != 0
1245 * - d = (distinct t_1 ... t_n)
1246 * - dmsk = dmask[class[t1]] & ... & dmask[class[t_n]]
1247 */
explain_distinct_via_dmask(egraph_t * egraph,composite_t * d,uint32_t dmsk,ivector_t * v)1248 static void explain_distinct_via_dmask(egraph_t *egraph, composite_t *d, uint32_t dmsk, ivector_t *v) {
1249 occ_t t, t1, t2;
1250 uint32_t i, j, m;
1251 composite_t *dpred;
1252 elabel_t x;
1253 int_hmap_t *imap;
1254 int_hmap_pair_t *p;
1255
1256 assert(dmsk != 0);
1257
1258 m = composite_arity(d);
1259
1260 i = ctz(dmsk);
1261 assert(i < egraph->dtable.npreds);
1262
1263 if (i == 0) {
1264 // t_1 ... t_m are equal to distinct constants a_1 ... a_m
1265 for (j=0; j<m; j++) {
1266 t1 = d->child[j];
1267 explain_eq(egraph, t1, constant_in_class(egraph, t1), v);
1268 }
1269
1270 } else {
1271 // dpred implies d
1272 dpred = egraph->dtable.distinct[i];
1273 assert(dpred != NULL && composite_kind(dpred) == COMPOSITE_DISTINCT);
1274
1275 // explain why dpred is true
1276 t = pos_occ(dpred->id);
1277 assert(egraph_label(egraph, t) == true_label);
1278 explain_eq(egraph, t, true_occ, v);
1279
1280 imap = egraph_get_imap(egraph);
1281 for (i=0; i<m; i++) {
1282 t1 = d->child[i];
1283 x = egraph_label(egraph, t1);
1284 p = int_hmap_get(imap, x);
1285 assert(p->val < 0); // otherwise equal terms t_i and t_j occur in d
1286 p->val = t1;
1287 }
1288
1289 m = composite_arity(dpred);
1290 for (i=0; i<m; i++) {
1291 t1 = dpred->child[i];
1292 x = egraph_label(egraph, t1);
1293 p = int_hmap_get(imap, x);
1294 t2 = p->val;
1295 if (t2 >= 0) {
1296 assert(egraph_equal_occ(egraph, t1, t2));
1297 explain_eq(egraph, t1, t2, v);
1298 }
1299 }
1300
1301 int_hmap_reset(imap);
1302 }
1303 }
1304
1305 #if 0
1306 // NOT USED
1307 /*
1308 * Explain distinct: general case
1309 */
1310 static void explain_distinct(egraph_t *egraph, composite_t *d) {
1311 occ_t t;
1312 uint32_t i, j, m;
1313 uint32_t *dmask, dmsk;
1314
1315 dmask = egraph->classes.dmask;
1316 m = composite_arity(d);
1317 assert(m > 0);
1318
1319 #ifndef NDEBUG
1320 for (i=0; i<m; i++) {
1321 assert(is_pos_occ(d->child[i]));
1322 }
1323 #endif
1324
1325 /*
1326 * try a cheap trick first: check whether all t_1 ... t_m are constant
1327 * or whether there's another atom (distinct u_1 ... u_p) that implies d
1328 */
1329 dmsk = ~((uint32_t) 0);
1330 i = 0;
1331 do {
1332 t = d->child[i];
1333 dmsk &= dmask[egraph_class(egraph, t)];
1334 i ++;
1335 } while (dmsk != 0 && i < m);
1336
1337 if (dmsk) {
1338 explain_distinct_via_dmask(egraph, d, dmsk);
1339 return;
1340 }
1341
1342 for (i=0; i<m; i++) {
1343 t = d->child[i];
1344 for (j=i+1; j<m; j++) {
1345 explain_diseq(egraph, t, d->child[j]);
1346 }
1347 }
1348 }
1349
1350
1351 // NOT USED
1352 /*
1353 * Explain a conflict between
1354 * - assertion (distinct t_1 ... t_n) == false
1355 * - and the fact that (t_j /= t_i) for all pairs
1356 */
1357 void egraph_explain_not_distinct_conflict(egraph_t *egraph, composite_t *d, ivector_t *v) {
1358 assert(egraph_equal_occ(egraph, pos_occ(d->id), false_occ));
1359 assert(egraph->expl_queue.size == 0);
1360
1361 explain_eq(egraph, pos_occ(d->id), false_occ, v);
1362 explain_distinct(egraph, d);
1363 ivector_reset(v);
1364 build_explanation_vector(egraph, v);
1365 }
1366
1367 #endif
1368
1369 /*
1370 * Check whether asserting equality (t1 == t2) is inconsistent
1371 * - if so, construct an explanation and store it in v
1372 * - i = index of the equality (t1 == t2) in egraph->stack.
1373 * Assumes t1 and t2 are not in the same class.
1374 */
egraph_inconsistent_edge(egraph_t * egraph,occ_t t1,occ_t t2,int32_t i,ivector_t * v)1375 bool egraph_inconsistent_edge(egraph_t *egraph, occ_t t1, occ_t t2, int32_t i, ivector_t *v) {
1376 occ_t aux;
1377 class_t c1, c2;
1378 uint32_t msk;
1379 composite_t *cmp;
1380
1381 assert(egraph->expl_queue.size == 0 && ! tst_bit(egraph->stack.mark, i));
1382
1383 egraph->top_id = INT32_MAX;
1384
1385 if (egraph_opposite_occ(egraph, t1, t2)) {
1386 // t1 == (not t2);
1387 ivector_reset(v);
1388 explain_eq(egraph, t1, t2, v);
1389 goto conflict;
1390 }
1391
1392 c1 = egraph_class(egraph, t1);
1393 c2 = egraph_class(egraph, t2);
1394 assert(c1 != c2);
1395
1396 msk = egraph->classes.dmask[c1] & egraph->classes.dmask[c2];
1397 if ((msk & 1) != 0) {
1398 ivector_reset(v);
1399 explain_diseq_via_constants(egraph, t1, t2, v);
1400 goto conflict;
1401 } else if (msk != 0) {
1402 assert(1 <= ctz(msk) && ctz(msk) < egraph->dtable.npreds);
1403 ivector_reset(v);
1404 explain_diseq_via_dmasks(egraph, t1, t2, ctz(msk), egraph->stack.top, v);
1405 goto conflict;
1406 }
1407
1408 cmp = congruence_table_find_eq(&egraph->ctable, t1, t2, egraph->terms.label);
1409 if (cmp != NULL && egraph_occ_is_false(egraph, pos_occ(cmp->id))) {
1410 // cmp is congruent to (eq t1 t2) and cmp == false
1411 ivector_reset(v);
1412 explain_eq(egraph, pos_occ(cmp->id), false_occ, v);
1413
1414 if (c1 != egraph_class(egraph, cmp->child[0])) {
1415 assert(c2 == egraph_class(egraph, cmp->child[0]));
1416 aux = t1; t1 = t2; t2 = aux;
1417 }
1418
1419 explain_eq(egraph, t1, cmp->child[0], v);
1420 explain_eq(egraph, t2, cmp->child[1], v);
1421 goto conflict;
1422 }
1423
1424 return false;
1425
1426 conflict:
1427 // add edge i to the explanation queue
1428 enqueue_edge(&egraph->expl_queue, egraph->stack.mark, i);
1429 build_explanation_vector(egraph, v);
1430
1431 return true;
1432 }
1433
1434
1435 /*
1436 * Check whether asserting (distinct t1 ... t_m) is inconsistent
1437 * - i.e., whether t_i and t_j are equal for i /= j
1438 * - if so construct an explanation for the conflict and store in in v
1439 * - d = distinct atom
1440 */
egraph_inconsistent_distinct(egraph_t * egraph,composite_t * d,ivector_t * v)1441 bool egraph_inconsistent_distinct(egraph_t *egraph, composite_t *d, ivector_t *v) {
1442 occ_t t, t1, t2;
1443 elabel_t x;
1444 uint32_t i, m;
1445 int_hmap_t *imap;
1446 int_hmap_pair_t *p;
1447
1448 assert(egraph->expl_queue.size == 0);
1449
1450 egraph->top_id = INT32_MAX;
1451
1452 imap = egraph_get_imap(egraph);
1453
1454 // check whether two terms have the same label
1455 m = composite_arity(d);
1456 for (i=0; i<m; i++) {
1457 t1 = d->child[i];
1458 x = egraph_label(egraph, t1);
1459 assert(x >= 0);
1460 p = int_hmap_get(imap, x);
1461 t2 = p->val;
1462 if (t2 >= 0) goto conflict; // t1 and t2 have label x
1463 p->val = t1;
1464 }
1465
1466 int_hmap_reset(imap);
1467
1468 return false;
1469
1470 conflict:
1471 int_hmap_reset(imap);
1472
1473 // conflict explanation is (t1 == t2) + (d == true)
1474 ivector_reset(v);
1475
1476 t = pos_occ(d->id);
1477 assert(egraph_occ_is_true(egraph, t));
1478 assert(egraph_equal_occ(egraph, t1, t2));
1479
1480 explain_eq(egraph, t, true_occ, v);
1481 explain_eq(egraph, t1, t2, v);
1482
1483 build_explanation_vector(egraph, v);
1484
1485 return true;
1486 }
1487
1488
1489
1490 /*
1491 * Test whether there is a term congruent to (eq t1 t2) and whether that
1492 * term is false.
1493 */
check_diseq1(egraph_t * egraph,occ_t t1,occ_t t2)1494 static bool check_diseq1(egraph_t *egraph, occ_t t1, occ_t t2) {
1495 composite_t *eq;
1496
1497 eq = congruence_table_find_eq(&egraph->ctable, t1, t2, egraph->terms.label);
1498 return eq != NULL_COMPOSITE && egraph_occ_is_false(egraph, pos_occ(eq->id));
1499 }
1500
1501
1502
1503
1504 /*
1505 * Check whether asserting not d, where d is (distinct t_1 ... t_m) causes a conflict,
1506 * i.e., whether (t_i != t_j) holds for all i < j.
1507 * - if so construct an explanation and store it in v (reset v first)
1508 * Warning: can be expensive if m is large
1509 *
1510 * Assumptions:
1511 * - t_1 ... t_m are not boolean (all are positive occurrences)
1512 * - class[t_i] != class[t_j] when i != j
1513 */
egraph_inconsistent_not_distinct(egraph_t * egraph,composite_t * d,ivector_t * v)1514 bool egraph_inconsistent_not_distinct(egraph_t *egraph, composite_t *d, ivector_t *v) {
1515 occ_t t, t1, t2;
1516 uint32_t i, j, m;
1517 uint32_t *dmask, dmsk;
1518
1519 assert(egraph->expl_queue.size == 0);
1520
1521 egraph->top_id = INT32_MAX;
1522
1523 dmask = egraph->classes.dmask;
1524 m = composite_arity(d);
1525 assert(m > 0);
1526
1527 #ifndef NDEBUG
1528 for (i=0; i<m; i++) {
1529 assert(is_pos_occ(d->child[i]));
1530 }
1531 #endif
1532
1533 /*
1534 * try a cheap trick first: check whether all t_1 ... t_m are constant
1535 * or whether there's another atom (distinct u_1 ... u_p) that implies d
1536 */
1537 dmsk = ~((uint32_t) 0);
1538 i = 0;
1539 do {
1540 t1 = d->child[i];
1541 dmsk &= dmask[egraph_class(egraph, t1)];
1542 i ++;
1543 } while (dmsk != 0 && i < m);
1544
1545 if (dmsk) {
1546 // cheap trick worked: conflict detected
1547 ivector_reset(v);
1548 explain_distinct_via_dmask(egraph, d, dmsk, v);
1549 goto conflict;
1550 }
1551
1552 /*
1553 * Cheap trick failed: check all the pairs
1554 */
1555 for (i=0; i<m; i++) {
1556 t1 = d->child[i];
1557 dmsk = dmask[egraph_class(egraph, t1)];
1558 for (j=i+1; j<m; j++) {
1559 t2 = d->child[j];
1560 if ((dmask[egraph_class(egraph, t2)] & dmsk) == 0 && ! check_diseq1(egraph, t1, t2)) {
1561 return false;
1562 }
1563 }
1564 }
1565
1566 /*
1567 * All pairs are distinct: build conflict explanation
1568 */
1569 ivector_reset(v);
1570 for (i=0; i<m; i++) {
1571 t1 = d->child[i];
1572 for (j=i+1; j<m; j++) {
1573 explain_diseq(egraph, t1, d->child[j], v);
1574 }
1575 }
1576
1577 conflict:
1578 // explain (d == false);
1579 t = pos_occ(d->id);
1580 assert(egraph_occ_is_false(egraph, t));
1581 explain_eq(egraph, t, false_occ, v);
1582
1583 // expand the explanations
1584 build_explanation_vector(egraph, v);
1585
1586 return true;
1587 }
1588
1589
1590
1591 /*
1592 * SUPPORT FOR EGRAPH/THEORY SOLVER RECONCILIATION
1593 */
1594
1595
1596 /*
1597 * Check whether the equation t1 == t2 is candidate for interface lemma
1598 */
interface_lemma_candidate(egraph_t * egraph,occ_t t1,occ_t t2)1599 static bool interface_lemma_candidate(egraph_t *egraph, occ_t t1, occ_t t2) {
1600 void *satellite;
1601 th_egraph_interface_t *interface;
1602 thvar_t x1, x2;
1603
1604 x1 = egraph_base_thvar(egraph, t1);
1605 x2 = egraph_base_thvar(egraph, t2);
1606
1607 if (x1 != null_thvar && x2 != null_thvar) {
1608 switch (egraph_type(egraph, t1)) {
1609 case ETYPE_INT:
1610 case ETYPE_REAL:
1611 satellite = egraph->th[ETYPE_REAL];
1612 interface = egraph->eg[ETYPE_REAL];
1613 return interface->equal_in_model(satellite, x1, x2);
1614
1615 case ETYPE_BV:
1616 satellite = egraph->th[ETYPE_BV];
1617 interface = egraph->eg[ETYPE_BV];
1618 return interface->equal_in_model(satellite, x1, x2);
1619
1620 default:
1621 break;
1622 }
1623 }
1624
1625 return false;
1626 }
1627
1628
1629 /*
1630 * Scan the explanation queue until we get an edge that can be used for interface lemma
1631 * - the returned edge must be larger than source and be an equality between
1632 * terms that have arithmetic or bit-vector variables
1633 * - return the index of that edge
1634 */
egraph_search_for_reconcile_edge(egraph_t * egraph,int32_t source)1635 static int32_t egraph_search_for_reconcile_edge(egraph_t *egraph, int32_t source) {
1636 equeue_elem_t *eq;
1637 byte_t *mark;
1638 ivector_t *queue;
1639 unsigned char *etag;
1640 expl_data_t *edata;
1641 composite_t **body;
1642 bool saved_short_cuts;
1643 eterm_t t1, t2;
1644 uint32_t k;
1645 int32_t i, found;
1646
1647 /*
1648 * We force short_cuts to false here since we're not
1649 * building an explanation.
1650 */
1651 saved_short_cuts = egraph->short_cuts;
1652 egraph->short_cuts = false;
1653
1654 eq = egraph->stack.eq;
1655 mark = egraph->stack.mark;
1656 etag = egraph->stack.etag;
1657 edata = egraph->stack.edata;
1658 body = egraph->terms.body;
1659 queue = &egraph->expl_queue;
1660
1661 found = -1;
1662
1663 for (k = 0; k < queue->size; k++) {
1664 i = queue->data[k];
1665 assert(i >= 0 && tst_bit(mark, i));
1666
1667 if (i >= source && interface_lemma_candidate(egraph, eq[i].lhs, eq[i].rhs)) {
1668 found = i;
1669 goto done;
1670 }
1671
1672 switch (etag[i]) {
1673 case EXPL_AXIOM:
1674 case EXPL_ASSERT:
1675 break;
1676
1677 case EXPL_EQ:
1678 explain_eq(egraph, edata[i].t[0], edata[i].t[1], NULL);
1679 break;
1680
1681 case EXPL_DISTINCT0:
1682 explain_diseq_via_constants(egraph, edata[i].t[0], edata[i].t[1], NULL);
1683 break;
1684
1685 case EXPL_DISTINCT1:
1686 case EXPL_DISTINCT2:
1687 case EXPL_DISTINCT3:
1688 case EXPL_DISTINCT4:
1689 case EXPL_DISTINCT5:
1690 case EXPL_DISTINCT6:
1691 case EXPL_DISTINCT7:
1692 case EXPL_DISTINCT8:
1693 case EXPL_DISTINCT9:
1694 case EXPL_DISTINCT10:
1695 case EXPL_DISTINCT11:
1696 case EXPL_DISTINCT12:
1697 case EXPL_DISTINCT13:
1698 case EXPL_DISTINCT14:
1699 case EXPL_DISTINCT15:
1700 case EXPL_DISTINCT16:
1701 case EXPL_DISTINCT17:
1702 case EXPL_DISTINCT18:
1703 case EXPL_DISTINCT19:
1704 case EXPL_DISTINCT20:
1705 case EXPL_DISTINCT21:
1706 case EXPL_DISTINCT22:
1707 case EXPL_DISTINCT23:
1708 case EXPL_DISTINCT24:
1709 case EXPL_DISTINCT25:
1710 case EXPL_DISTINCT26:
1711 case EXPL_DISTINCT27:
1712 case EXPL_DISTINCT28:
1713 case EXPL_DISTINCT29:
1714 case EXPL_DISTINCT30:
1715 case EXPL_DISTINCT31:
1716 explain_diseq_via_dmasks(egraph, edata[i].t[0], edata[i].t[1], (uint32_t) (etag[i] - EXPL_DISTINCT0), i, NULL);
1717 break;
1718
1719 case EXPL_SIMP_OR:
1720 // eq[i].lhs = (or ...), rhs == false or term occurrence
1721 t1 = term_of_occ(eq[i].lhs);
1722 assert(composite_body(body[t1]));
1723 if (eq[i].rhs == false_occ) {
1724 explain_simp_or_false(egraph, body[t1], NULL);
1725 } else {
1726 explain_simp_or(egraph, body[t1], eq[i].rhs, NULL);
1727 }
1728 break;
1729
1730 case EXPL_BASIC_CONGRUENCE:
1731 t1 = term_of_occ(eq[i].lhs);
1732 t2 = term_of_occ(eq[i].rhs);
1733 explain_congruence(egraph, body[t1], body[t2], NULL);
1734 break;
1735
1736 case EXPL_EQ_CONGRUENCE1:
1737 t1 = term_of_occ(eq[i].lhs);
1738 t2 = term_of_occ(eq[i].rhs);
1739 explain_eq_congruence1(egraph, body[t1], body[t2], NULL);
1740 break;
1741
1742 case EXPL_EQ_CONGRUENCE2:
1743 t1 = term_of_occ(eq[i].lhs);
1744 t2 = term_of_occ(eq[i].rhs);
1745 explain_eq_congruence2(egraph, body[t1], body[t2], NULL);
1746 break;
1747
1748 case EXPL_ITE_CONGRUENCE1:
1749 t1 = term_of_occ(eq[i].lhs);
1750 t2 = term_of_occ(eq[i].rhs);
1751 explain_ite_congruence1(egraph, body[t1], body[t2], NULL);
1752 break;
1753
1754 case EXPL_ITE_CONGRUENCE2:
1755 t1 = term_of_occ(eq[i].lhs);
1756 t2 = term_of_occ(eq[i].rhs);
1757 explain_ite_congruence2(egraph, body[t1], body[t2], NULL);
1758 break;
1759
1760 case EXPL_OR_CONGRUENCE:
1761 t1 = term_of_occ(eq[i].lhs);
1762 t2 = term_of_occ(eq[i].rhs);
1763 explain_or_congruence(egraph, body[t1], body[t2], edata[i].ptr, NULL);
1764 break;
1765
1766 case EXPL_DISTINCT_CONGRUENCE:
1767 t1 = term_of_occ(eq[i].lhs);
1768 t2 = term_of_occ(eq[i].rhs);
1769 explain_distinct_congruence(egraph, body[t1], body[t2], edata[i].ptr, NULL);
1770 break;
1771
1772 case EXPL_ARITH_PROPAGATION:
1773 case EXPL_BV_PROPAGATION:
1774 case EXPL_FUN_PROPAGATION:
1775 // Don't explore this
1776 break;
1777
1778 case EXPL_RECONCILE:
1779 found = i;
1780 goto done;
1781 }
1782 }
1783
1784 done:
1785 // clear all the marks
1786 for (k=0; k<queue->size; k++) {
1787 i = queue->data[k];
1788 assert(i >= 0 && tst_bit(mark, i));
1789 clr_bit(mark, i);
1790 }
1791 ivector_reset(queue);
1792
1793 assert(found >= 0);
1794
1795 // restore the short_cuts flag
1796 egraph->short_cuts = saved_short_cuts;
1797
1798 return found;
1799 }
1800
1801
1802 /*
1803 * Return an edge that's an antecedent of edge i and is an interface lemma candidate
1804 * - source must be the index of the EXPL_RECONCILE edge that triggered a conflict
1805 * - i must be the index of the conflict edge
1806 */
egraph_get_reconcile_edge(egraph_t * egraph,int32_t source,int32_t i)1807 int32_t egraph_get_reconcile_edge(egraph_t *egraph, int32_t source, int32_t i) {
1808 assert(0 <= i && i < egraph->stack.top && source <= i);
1809 assert(egraph->expl_queue.size == 0 && ! tst_bit(egraph->stack.mark, i));
1810 enqueue_edge(&egraph->expl_queue, egraph->stack.mark, i);
1811
1812 return egraph_search_for_reconcile_edge(egraph, source);
1813 }
1814
1815
1816