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