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 CONSTRUCTION AND MAIN OPERATIONS
21  */
22 
23 #include <stdint.h>
24 #include <stdbool.h>
25 #include <assert.h>
26 #include <inttypes.h>
27 
28 #include "io/tracer.h"
29 #include "solvers/egraph/composites.h"
30 #include "solvers/egraph/egraph.h"
31 #include "solvers/egraph/egraph_explanations.h"
32 #include "solvers/egraph/egraph_utils.h"
33 #include "solvers/egraph/theory_explanations.h"
34 #include "utils/bit_tricks.h"
35 #include "utils/hash_functions.h"
36 #include "utils/index_vectors.h"
37 #include "utils/memalloc.h"
38 #include "utils/ptr_partitions.h"
39 
40 #include "api/yices_globals.h"
41 #include "mt/thread_macros.h"
42 
43 #define TRACE 0
44 #define TRACE_FCHECK 0
45 
46 #if TRACE || TRACE_FCHECK
47 
48 #include <stdio.h>
49 
50 #include "solvers/cdcl/smt_core_printer.h"
51 #include "solvers/egraph/egraph_printer.h"
52 #include "solvers/cdcl/smt_core_printer.h"
53 
54 #endif
55 
56 
57 /*
58  * Select variant implementations
59  */
60 #define CONSERVATIVE_DISEQ_AXIOMS 0
61 
62 
63 /*****************
64  *  CLASS TABLE  *
65  ****************/
66 
67 /*
68  * Initialization: n == initial size
69  */
init_class_table(class_table_t * tbl,uint32_t n)70 static void init_class_table(class_table_t *tbl, uint32_t n) {
71   uint32_t i;
72   assert(n <  MAX_CLASS_TABLE_SIZE);
73 
74   tbl->size = n;
75   tbl->nclasses = 0;
76 
77   tbl->root = (occ_t *) safe_malloc(n * sizeof(occ_t));
78   tbl->dmask = (uint32_t *) safe_malloc(n * sizeof(uint32_t));
79   tbl->parents = (use_vector_t *) safe_malloc(n * sizeof(use_vector_t));
80   tbl->etype = (unsigned char *) safe_malloc(n * sizeof(unsigned char));
81   tbl->thvar = (thvar_t *) safe_malloc(n * sizeof(thvar_t));
82 
83   // initialize all parent vectors (all empty)
84   for (i=0; i<n; i++) {
85     init_use_vector(tbl->parents + i, 0);
86   }
87 }
88 
89 
90 /*
91  * Increase size by 50%
92  */
extend_class_table(class_table_t * tbl)93 static void extend_class_table(class_table_t *tbl) {
94   uint32_t i, n;
95 
96   n = tbl->size + 1;
97   n += n>>1;
98 
99   if (n >= MAX_CLASS_TABLE_SIZE) {
100     out_of_memory();
101   }
102 
103   tbl->root = (occ_t *) safe_realloc(tbl->root, n * sizeof(occ_t));
104   tbl->dmask = (uint32_t *) safe_realloc(tbl->dmask, n * sizeof(eterm_t));
105   tbl->parents = (use_vector_t *) safe_realloc(tbl->parents, n * sizeof(use_vector_t));
106   tbl->etype = (unsigned char *) safe_realloc(tbl->etype, n * sizeof(unsigned char));
107   tbl->thvar = (thvar_t *) safe_realloc(tbl->thvar, n * sizeof(thvar_t));
108 
109   // initialize the new parent vectors (all empty)
110   for (i=tbl->size; i<n; i++) {
111     init_use_vector(tbl->parents + i, 0);
112   }
113 
114   tbl->size = n;
115 }
116 
117 
118 /*
119  * Allocate a new class
120  * - nothing is initialized, except the parent vector
121  * - the parent vector is empty
122  */
alloc_class(class_table_t * tbl)123 static class_t alloc_class(class_table_t *tbl) {
124   class_t i;
125 
126   i = tbl->nclasses;
127   if (i >= tbl->size) {
128     extend_class_table(tbl);
129   }
130 
131   tbl->nclasses ++;
132   assert(tbl->parents[i].nelems == 0);
133   return i;
134 }
135 
136 
137 
138 /*
139  * Initialize a singleton class c with unique element pos_occ(t)
140  * - dmask must be 0x1 if t is a constant, 0 otherwise
141  * - tau = type of t
142  * - x = theory variable of t
143  */
init_class(class_table_t * tbl,class_t c,eterm_t t,uint32_t dmask,etype_t tau,thvar_t x)144 static inline void init_class(class_table_t *tbl, class_t c, eterm_t t, uint32_t dmask, etype_t tau, thvar_t x) {
145   tbl->root[c] = pos_occ(t);
146   tbl->dmask[c] = dmask;
147   tbl->etype[c] = tau;
148   tbl->thvar[c] = x;
149 }
150 
151 
152 /*
153  * Cleanup class c: free its parent vector if it's large
154  * - its use vector must be empty and it must contain a single term
155  */
free_parents(class_table_t * tbl,class_t c)156 static void free_parents(class_table_t *tbl, class_t c) {
157   assert(0 < c && c < tbl->nclasses && tbl->parents[c].nelems == 0);
158 
159   // to save memory: free parent vector if it's large
160   if (tbl->parents[c].size >= PARENT_DELETION_SIZE) {
161     delete_use_vector(tbl->parents + c);
162     init_use_vector(tbl->parents + c, 0);
163   } else {
164     reset_use_vector(tbl->parents + c);
165   }
166 }
167 
168 
169 
170 
171 /*
172  * Deletion
173  */
delete_class_table(class_table_t * tbl)174 static void delete_class_table(class_table_t *tbl) {
175   uint32_t i;
176 
177   for (i=0; i<tbl->size; i++) {
178     delete_use_vector(tbl->parents + i);
179   }
180   safe_free(tbl->parents);
181   safe_free(tbl->root);
182   safe_free(tbl->dmask);
183   safe_free(tbl->etype);
184   safe_free(tbl->thvar);
185 
186   tbl->root = NULL;
187   tbl->dmask = NULL;
188   tbl->parents = NULL;
189   tbl->etype = NULL;
190   tbl->thvar = NULL;
191 }
192 
193 
194 /*
195  * Reset the class table
196  */
reset_class_table(class_table_t * tbl)197 static void reset_class_table(class_table_t *tbl) {
198   uint32_t i;
199 
200   for (i=0; i<tbl->nclasses; i++) {
201     if (tbl->parents[i].size >= PARENT_DELETION_SIZE) {
202       delete_use_vector(tbl->parents + i);
203       init_use_vector(tbl->parents + i, 0);
204     } else {
205       reset_use_vector(tbl->parents + i);
206     }
207   }
208 
209   tbl->nclasses = 0;
210 }
211 
212 
213 
214 /****************
215  *  TERM TABLE  *
216  ***************/
217 
218 /*
219  * Initialization:
220  * - n = initial size.
221  */
init_eterm_table(eterm_table_t * tbl,uint32_t n)222 static void init_eterm_table(eterm_table_t *tbl, uint32_t n) {
223   assert(n < MAX_ETERM_TABLE_SIZE);
224 
225   tbl->size = n;
226   tbl->nterms = 0;
227 
228   tbl->body = (composite_t **) safe_malloc(n * sizeof(composite_t *));
229   tbl->label = (elabel_t *) safe_malloc(n * sizeof(elabel_t));
230   tbl->next = (occ_t *) safe_malloc(n * sizeof(occ_t));
231   tbl->edge = (int32_t *) safe_malloc(n * sizeof(int32_t));
232   tbl->thvar = (thvar_t *) safe_malloc(n * sizeof(thvar_t));
233   tbl->mark = allocate_bitvector(n);
234   tbl->real_type = (type_t *) safe_malloc(n * sizeof(type_t));
235 }
236 
237 /*
238  * Increase size by 50%
239  */
extend_eterm_table(eterm_table_t * tbl)240 static void extend_eterm_table(eterm_table_t *tbl) {
241   uint32_t n;
242 
243   n = tbl->size + 1;
244   n += n >> 1;
245 
246   if (n >= MAX_ETERM_TABLE_SIZE) {
247     out_of_memory();
248   }
249 
250   tbl->size = n;
251 
252   tbl->body = (composite_t **) safe_realloc(tbl->body, n * sizeof(composite_t *));
253   tbl->label = (elabel_t *) safe_realloc(tbl->label, n * sizeof(elabel_t));
254   tbl->next = (occ_t *) safe_realloc(tbl->next, n * sizeof(occ_t));
255   tbl->edge = (int32_t *) safe_realloc(tbl->edge, n * sizeof(int32_t));
256   tbl->thvar = (thvar_t *) safe_realloc(tbl->thvar, n * sizeof(thvar_t));
257   tbl->mark = extend_bitvector(tbl->mark, n);
258   tbl->real_type = (type_t *) safe_realloc(tbl->real_type, n * sizeof(type_t));
259 }
260 
261 
262 /*
263  * Allocate a new term with the following initialization:
264  * - body = cmp
265  * - edge = null_edge
266  * - thvar = null_var
267  * - label = null_label
268  * - successor = itself
269  * - real_type = NULL_TYPE
270  */
new_eterm(eterm_table_t * tbl,composite_t * b)271 static eterm_t new_eterm(eterm_table_t *tbl, composite_t *b) {
272   eterm_t t;
273 
274   t = tbl->nterms;
275   tbl->nterms ++;
276   if (t >= tbl->size) {
277     extend_eterm_table(tbl);
278   }
279 
280   tbl->body[t] = b;
281   tbl->label[t] = null_label;
282   tbl->next[t] = pos_occ(t);
283   tbl->edge[t] = null_edge;
284   tbl->thvar[t] = null_thvar;
285   clr_bit(tbl->mark, t);
286   tbl->real_type[t] = NULL_TYPE;
287 
288   return t;
289 }
290 
291 
292 /*
293  * Delete the full table
294  */
delete_eterm_table(eterm_table_t * tbl)295 static void delete_eterm_table(eterm_table_t *tbl) {
296   uint32_t i, n;
297 
298   n = tbl->nterms;
299   for (i=0; i<n; i++) {
300     if (composite_body(tbl->body[i])) {
301       safe_free(tbl->body[i]);
302     }
303   }
304 
305   safe_free(tbl->body);
306   safe_free(tbl->label);
307   safe_free(tbl->next);
308   safe_free(tbl->edge);
309   safe_free(tbl->thvar);
310   delete_bitvector(tbl->mark);
311   safe_free(tbl->real_type);
312 
313   tbl->body = NULL;
314   tbl->label = NULL;
315   tbl->next = NULL;
316   tbl->edge = NULL;
317   tbl->thvar = NULL;
318   tbl->mark = NULL;
319   tbl->real_type = NULL;
320 }
321 
322 
323 
324 /*
325  * Reset the term table: remove all terms
326  * - atoms are deleted by emptying the egraph's atom store
327  *   so we don't delete them here
328  */
reset_eterm_table(eterm_table_t * tbl)329 static void reset_eterm_table(eterm_table_t *tbl) {
330   uint32_t i, n;
331 
332   n = tbl->nterms;
333   for (i=0; i<n; i++) {
334     if (composite_body(tbl->body[i])) {
335       safe_free(tbl->body[i]);
336     }
337   }
338 
339   tbl->nterms = 0;
340 }
341 
342 
343 
344 
345 /********************
346  *  DISTINCT TABLE  *
347  *******************/
348 
init_distinct_table(distinct_table_t * tbl)349 static void init_distinct_table(distinct_table_t *tbl) {
350   tbl->npreds = 1;
351   tbl->distinct[0] = NULL;
352 }
353 
reset_distinct_table(distinct_table_t * tbl)354 static inline void reset_distinct_table(distinct_table_t *tbl) {
355   init_distinct_table(tbl);
356 }
357 
358 
359 
360 /**********************
361  *  LAMBDA TAG TABLE  *
362  *********************/
363 
364 /*
365  * Allocate and initialize a descriptor:
366  * - n = arity
367  * - dom[0 ... n-1] = types
368  */
new_ltag_desc(uint32_t n,type_t * dom)369 static ltag_desc_t *new_ltag_desc(uint32_t n, type_t *dom) {
370   ltag_desc_t *tmp;
371   uint32_t i;
372 
373   if (n > MAX_LTAG_DESC_ARITY) {
374     /*
375      * This should never happen since n <= YICES_MAX_ARITY < MAX_LTAG_DESC_ARITY.
376      * But we may change this one day.
377      */
378     out_of_memory();
379   }
380 
381   tmp = (ltag_desc_t *) safe_malloc(sizeof(ltag_desc_t) + n * sizeof(type_t));
382   tmp->arity = n;
383   for (i=0; i<n; i++) {
384     tmp->dom[i] = dom[i];
385   }
386 
387   return tmp;
388 }
389 
390 
391 /*
392  * Check whether d matches n and dom
393  */
ltag_desc_matches(ltag_desc_t * d,uint32_t n,type_t * dom)394 static bool ltag_desc_matches(ltag_desc_t *d, uint32_t n, type_t *dom) {
395   uint32_t i;
396 
397   if (d->arity != n) {
398     return false;
399   }
400 
401   for (i=0; i<n; i++) {
402     if (dom[i] != d->dom[i]) {
403       return false;
404     }
405   }
406 
407   return true;
408 }
409 
410 
411 /*
412  * Initialize/delete/reset
413  */
init_ltag_table(ltag_table_t * tbl)414 static void init_ltag_table(ltag_table_t *tbl) {
415   tbl->size = 0;
416   tbl->ntags = 0;
417   tbl->data = NULL;
418 }
419 
delete_ltag_table(ltag_table_t * tbl)420 static void delete_ltag_table(ltag_table_t *tbl) {
421   uint32_t i, n;
422 
423   n = tbl->ntags;
424   for (i=0; i<n; i++) {
425     safe_free(tbl->data[i]);
426   }
427   safe_free(tbl->data);
428   tbl->data = NULL;
429 }
430 
reset_ltag_table(ltag_table_t * tbl)431 static void reset_ltag_table(ltag_table_t *tbl) {
432   uint32_t i, n;
433 
434   n = tbl->ntags;
435   for (i=0; i<n; i++) {
436     safe_free(tbl->data[i]);
437   }
438   tbl->ntags = 0;
439 }
440 
441 
442 /*
443  * Make room in tbl
444  */
extend_ltag_table(ltag_table_t * tbl)445 static void extend_ltag_table(ltag_table_t *tbl) {
446   uint32_t n;
447 
448   n = tbl->size;
449   if (n == 0) {
450     // start with the default size
451     n = DEF_LTAG_TABLE_SIZE;
452     assert(n <= MAX_LTAG_TABLE_SIZE);
453 
454     tbl->data = (ltag_desc_t **) safe_malloc(n * sizeof(ltag_desc_t *));
455     tbl->size = n;
456 
457   } else {
458     // increase size by 50%
459     n ++;
460     n += n >> 1;
461 
462     if (n > MAX_LTAG_TABLE_SIZE) {
463       out_of_memory();
464     }
465 
466     tbl->data = (ltag_desc_t **) safe_realloc(tbl->data, n * sizeof(ltag_desc_t *));
467     tbl->size = n;
468   }
469 }
470 
471 
472 /*
473  * Allocate a new tag and build the corresponding descriptor
474  * - n = arity
475  * - dom[0 ... n-1] = types
476  */
ltag_table_add_descriptor(ltag_table_t * tbl,uint32_t n,type_t * dom)477 static int32_t ltag_table_add_descriptor(ltag_table_t *tbl, uint32_t n, type_t *dom) {
478   uint32_t i;
479 
480   i = tbl->ntags;
481   if (i == tbl->size) {
482     extend_ltag_table(tbl);
483   }
484   assert(i < tbl->size);
485 
486   tbl->data[i] = new_ltag_desc(n, dom);
487   tbl->ntags ++;
488 
489   return i;
490 }
491 
492 
493 
494 /*
495  * Get a tag for dom[0 ... n-1]
496  */
ltag_table_get_tag(ltag_table_t * tbl,uint32_t n,type_t * dom)497 static int32_t ltag_table_get_tag(ltag_table_t *tbl, uint32_t n, type_t *dom) {
498   uint32_t i, ntags;
499 
500   ntags = tbl->ntags;
501   for (i=0; i<ntags; i++) {
502     if (ltag_desc_matches(tbl->data[i], n, dom)) {
503       return i;
504     }
505   }
506 
507   return ltag_table_add_descriptor(tbl, n, dom);
508 }
509 
510 
511 
512 /*
513  * Search for a tag:
514  * - return -1 if nothing matches dom[0 ... n-1] in the table
515  */
ltag_table_find_tag(ltag_table_t * tbl,uint32_t n,type_t * dom)516 static int32_t ltag_table_find_tag(ltag_table_t *tbl, uint32_t n, type_t *dom) {
517   uint32_t i, ntags;
518 
519   ntags = tbl->ntags;
520   for (i=0; i<ntags; i++) {
521     if (ltag_desc_matches(tbl->data[i], n, dom)) {
522       return i;
523     }
524   }
525 
526   return -1;
527 }
528 
529 
530 /*
531  * Get tag for the function type tau:
532  * - types = the corresponding type table
533  */
lambda_tag_for_type(ltag_table_t * tbl,type_table_t * types,type_t tau)534 static int32_t lambda_tag_for_type(ltag_table_t *tbl, type_table_t *types, type_t tau) {
535   function_type_t *d;
536 
537   d = function_type_desc(types, tau);
538   return ltag_table_get_tag(tbl, d->ndom, d->domain);
539 }
540 
541 
542 /*
543  * Check whether there's an existing tag for function type tau
544  * - return the tag if it's found or -1 otherwise
545  */
find_lambda_tag_for_type(ltag_table_t * tbl,type_table_t * types,type_t tau)546 static int32_t find_lambda_tag_for_type(ltag_table_t *tbl, type_table_t *types, type_t tau) {
547   function_type_t *d;
548 
549   d = function_type_desc(types, tau);
550   return ltag_table_find_tag(tbl, d->ndom, d->domain);
551 }
552 
553 
554 
555 
556 /***********************
557  *  PROPAGATION QUEUE  *
558  **********************/
559 
560 /*
561  * Initialize:
562  * - n = initial size
563  * - m = initial number of levels
564  */
init_egraph_stack(egraph_stack_t * stack,uint32_t n,uint32_t m)565 static void init_egraph_stack(egraph_stack_t *stack, uint32_t n, uint32_t m) {
566   assert(n < MAX_EGRAPH_STACK_SIZE && 0 < m && m < MAX_EGRAPH_STACK_LEVELS);
567 
568   stack->eq = (equeue_elem_t *) safe_malloc(n * sizeof(equeue_elem_t));
569   stack->etag = (unsigned char *) safe_malloc(n * sizeof(unsigned char));
570   stack->edata = (expl_data_t *) safe_malloc(n * sizeof(expl_data_t));
571   stack->mark = allocate_bitvector(n);
572   stack->top = 0;
573   stack->prop_ptr = 0;
574   stack->size = n;
575 
576   stack->level_index = (uint32_t *) safe_malloc(m * sizeof(uint32_t));
577   stack->level_index[0] = 0;
578   stack->nlevels = m;
579 }
580 
581 
582 /*
583  * Extend the stack: increase size by 50%
584  */
extend_egraph_stack(egraph_stack_t * stack)585 static void extend_egraph_stack(egraph_stack_t *stack) {
586   uint32_t n;
587 
588   n = stack->size + 1;
589   n += n >> 1;
590 
591   if (n >= MAX_EGRAPH_STACK_SIZE) {
592     out_of_memory();
593   }
594 
595   stack->eq = (equeue_elem_t *) safe_realloc(stack->eq, n * sizeof(equeue_elem_t));
596   stack->etag = (unsigned char *) safe_realloc(stack->etag, n * sizeof(unsigned char));
597   stack->edata = (expl_data_t *) safe_realloc(stack->edata, n * sizeof(expl_data_t));
598   stack->mark = extend_bitvector(stack->mark, n);
599   stack->size = n;
600 }
601 
602 
603 /*
604  * Increase the number of levels by 50%
605  */
increase_egraph_stack_levels(egraph_stack_t * stack)606 static void increase_egraph_stack_levels(egraph_stack_t *stack) {
607   uint32_t n;
608 
609   n = stack->nlevels + 1;
610   n += n>>1;
611 
612   if (n >= MAX_EGRAPH_STACK_LEVELS) {
613     out_of_memory();
614   }
615 
616   stack->level_index = (uint32_t *) safe_realloc(stack->level_index, n * sizeof(uint32_t));
617   stack->nlevels = n;
618 }
619 
620 
621 
622 /*
623  * Push equality (t1 == t2) on top of the stack
624  * - return the new edge's index
625  * - explanation for the new edge must be set outside this function.
626  */
egraph_stack_push_eq(egraph_stack_t * stack,occ_t t1,occ_t t2)627 static int32_t egraph_stack_push_eq(egraph_stack_t *stack, occ_t t1, occ_t t2) {
628   uint32_t i;
629 
630   i = stack->top;
631   if (i >= stack->size) {
632     extend_egraph_stack(stack);
633   }
634   clr_bit(stack->mark, i);
635   stack->top = i+1;
636   stack->eq[i].lhs = t1;
637   stack->eq[i].rhs = t2;
638 
639   return i;
640 }
641 
642 
643 
644 /*
645  * Delete the stack
646  */
delete_egraph_stack(egraph_stack_t * stack)647 static void delete_egraph_stack(egraph_stack_t *stack) {
648   safe_free(stack->eq);
649   safe_free(stack->etag);
650   safe_free(stack->edata);
651   safe_free(stack->level_index);
652   delete_bitvector(stack->mark);
653 
654   stack->eq = NULL;
655   stack->etag = NULL;
656   stack->edata = NULL;
657   stack->level_index = NULL;
658   stack->mark = NULL;
659 }
660 
661 
662 
663 /*
664  * Empty the stack
665  */
reset_egraph_stack(egraph_stack_t * stack)666 static void reset_egraph_stack(egraph_stack_t *stack) {
667   stack->top = 0;
668   stack->prop_ptr = 0;
669   stack->level_index[0] = 0;
670 }
671 
672 
673 
674 
675 /****************
676  *  UNDO STACK  *
677  ***************/
678 
679 /*
680  * Initialize: n = size, m = number of levels
681  */
init_undo_stack(undo_stack_t * stack,uint32_t n,uint32_t m)682 static void init_undo_stack(undo_stack_t *stack, uint32_t n, uint32_t m) {
683   assert(n < MAX_EGRAPH_STACK_SIZE && 0 < m && m < MAX_EGRAPH_STACK_LEVELS);
684 
685   stack->tag = (unsigned char *) safe_malloc(n * sizeof(unsigned char));
686   stack->data = (undo_t *) safe_malloc(n * sizeof(undo_t));
687   stack->top = 0;
688   stack->size = n;
689 
690   stack->level_index = (uint32_t  *) safe_malloc(m * sizeof(uint32_t));
691   stack->level_index[0] = 0;
692   stack->nlevels = m;
693 }
694 
695 /*
696  * Extend by 50%
697  */
extend_undo_stack(undo_stack_t * stack)698 static void extend_undo_stack(undo_stack_t *stack) {
699   uint32_t n;
700 
701   n = stack->size + 1;
702   n += n >> 1;
703 
704   if (n >= MAX_EGRAPH_STACK_SIZE) {
705     out_of_memory();
706   }
707 
708   stack->tag = (unsigned char *) safe_realloc(stack->tag, n * sizeof(unsigned char));
709   stack->data = (undo_t *) safe_realloc(stack->data, n * sizeof(undo_t));
710   stack->size = n;
711 }
712 
713 /*
714  * Increase the number of levels
715  */
increase_undo_stack_levels(undo_stack_t * stack)716 static void increase_undo_stack_levels(undo_stack_t *stack) {
717   uint32_t n;
718 
719   n = stack->nlevels + 1;
720   n += n >> 1;
721 
722   if (n >= MAX_EGRAPH_STACK_LEVELS) {
723     out_of_memory();
724   }
725 
726   stack->level_index = (uint32_t *) safe_realloc(stack->level_index, n * sizeof(uint32_t));
727   stack->nlevels = n;
728 }
729 
730 
731 
732 /*
733  * Push undo objects
734  */
undo_stack_get_top(undo_stack_t * stack)735 static inline uint32_t undo_stack_get_top(undo_stack_t *stack) {
736   uint32_t i;
737 
738   i = stack->top;
739   if (i >= stack->size) {
740     extend_undo_stack(stack);
741   }
742   stack->top = i+1;
743 
744   return i;
745 }
746 
747 
748 /*
749  * Save t and its class label l, just before the class of t is merged
750  * with another class. This happens when an equality (t == u) is processed,
751  */
undo_stack_push_merge(undo_stack_t * stack,occ_t t,elabel_t l)752 static void undo_stack_push_merge(undo_stack_t *stack, occ_t t, elabel_t l) {
753   uint32_t i;
754 
755   i = undo_stack_get_top(stack);
756   stack->tag[i] = UNDO_MERGE;
757   stack->data[i].merge.saved_occ = t;
758   stack->data[i].merge.saved_label = l;
759 }
760 
761 
762 /*
763  * Assertion (distinct t_0 ... t_n-1) == true
764  * - the atom can be recovered from the distinct_table so
765  * we just need to put a mark that DISTINCT was asserted
766  */
undo_stack_push_distinct(undo_stack_t * stack)767 static void undo_stack_push_distinct(undo_stack_t *stack) {
768   uint32_t i;
769 
770   i = undo_stack_get_top(stack);
771   stack->tag[i] = UNDO_DISTINCT;
772 }
773 
774 // push pointer + tag
undo_stack_push_ptr(undo_stack_t * stack,void * p,undo_tag_t tag)775 static void undo_stack_push_ptr(undo_stack_t *stack, void *p, undo_tag_t tag) {
776   uint32_t i;
777 
778   i = undo_stack_get_top(stack);
779   stack->tag[i] = tag;
780   stack->data[i].ptr = p;
781 }
782 
783 /*
784  * UNDO_SIMPLIFY means that cmp was simplified and removed from the congruence
785  * table and use vectors (outside of a merge-class operation). On backtracking,
786  * we need to put cmp back into both tables.
787  */
undo_stack_push_composite(undo_stack_t * stack,composite_t * cmp)788 static inline void undo_stack_push_composite(undo_stack_t *stack, composite_t *cmp) {
789   undo_stack_push_ptr(stack, cmp, UNDO_SIMPLIFY);
790 }
791 
792 
793 /*
794  * Delete
795  */
delete_undo_stack(undo_stack_t * stack)796 static void delete_undo_stack(undo_stack_t *stack) {
797   safe_free(stack->tag);
798   safe_free(stack->data);
799   safe_free(stack->level_index);
800 
801   stack->tag = NULL;
802   stack->data = NULL;
803   stack->level_index = NULL;
804 }
805 
806 
807 /*
808  * Empty the stack
809  */
reset_undo_stack(undo_stack_t * stack)810 static void reset_undo_stack(undo_stack_t *stack) {
811   stack->top = 0;
812   stack->level_index[0] = 0;
813 }
814 
815 
816 /*****************
817  *  TRAIL STACK  *
818  ****************/
819 
820 /*
821  * Initialize a trail stack: size = 0
822  */
init_egraph_trail(egraph_trail_stack_t * stack)823 static void init_egraph_trail(egraph_trail_stack_t *stack) {
824   stack->size = 0;
825   stack->top = 0;
826   stack->data = NULL;
827 }
828 
829 
830 /*
831  * Save level:
832  * - nt = number of terms
833  * - p = propagation pointer
834  */
egraph_trail_save(egraph_trail_stack_t * stack,uint32_t nt,uint32_t p)835 static void egraph_trail_save(egraph_trail_stack_t *stack, uint32_t nt, uint32_t p) {
836   uint32_t i, n;
837 
838   i = stack->top;
839   n = stack->size;
840   if (i == n) {
841     if (n == 0) {
842       n = DEFAULT_EGRAPH_TRAIL_SIZE;
843     } else {
844       n += n;
845       if (n >= MAX_EGRAPH_TRAIL_SIZE) {
846         out_of_memory();
847       }
848     }
849     stack->data = (egraph_trail_t *) safe_realloc(stack->data, n * sizeof(egraph_trail_t));
850     stack->size = n;
851   }
852   stack->data[i].nterms = nt;
853   stack->data[i].prop_ptr = p;
854 
855   stack->top = i + 1;
856 }
857 
858 
859 /*
860  * Get top record
861  */
egraph_trail_top(egraph_trail_stack_t * stack)862 static inline egraph_trail_t *egraph_trail_top(egraph_trail_stack_t *stack) {
863   assert(stack->top > 0);
864   return stack->data + (stack->top - 1);
865 }
866 
867 
868 /*
869  * Remove top record
870  */
egraph_trail_pop(egraph_trail_stack_t * stack)871 static inline void egraph_trail_pop(egraph_trail_stack_t *stack) {
872   assert(stack->top > 0);
873   stack->top --;
874 }
875 
876 
877 /*
878  * Empty the stack
879  */
reset_egraph_trail(egraph_trail_stack_t * stack)880 static inline void reset_egraph_trail(egraph_trail_stack_t *stack) {
881   stack->top = 0;
882 }
883 
884 /*
885  * Delete
886  */
delete_egraph_trail(egraph_trail_stack_t * stack)887 static inline void delete_egraph_trail(egraph_trail_stack_t *stack) {
888   safe_free(stack->data);
889   stack->data = NULL;
890 }
891 
892 
893 
894 /***********************
895  *  STATISTICS RECORD  *
896  **********************/
897 
898 /*
899  * Initialize all counters to 0
900  */
init_egraph_stats(egraph_stats_t * s)901 static void init_egraph_stats(egraph_stats_t *s) {
902   s->app_reductions = 0;
903 
904   s->eq_props = 0;
905   s->th_props = 0;
906   s->th_conflicts = 0;
907   s->nd_lemmas = 0;
908 
909   s->aux_eqs = 0;
910   s->boolack_lemmas = 0;
911   s->ack_lemmas = 0;
912 
913   s->final_checks = 0;
914   s->interface_eqs = 0;
915 }
916 
917 /*
918  * Reset: same thing
919  */
reset_egraph_stats(egraph_stats_t * s)920 static inline void reset_egraph_stats(egraph_stats_t *s) {
921   init_egraph_stats(s);
922 }
923 
924 
925 
926 
927 
928 
929 /*************
930  *   MODEL   *
931  ************/
932 
933 /*
934  * Initialize mdl: no memory is allocated yet.
935  */
init_egraph_model(egraph_model_t * mdl)936 static void init_egraph_model(egraph_model_t *mdl) {
937   mdl->value = NULL;
938   mdl->pstore = NULL;
939   mdl->fval_maker = NULL;
940   init_ivector(&mdl->root_classes, 0);
941   init_ivector(&mdl->rank_ctr, 0);
942   q_init(&mdl->arith_buffer);
943   init_bvconstant(&mdl->bv_buffer);
944 }
945 
946 
947 /*
948  * Delete mdl: free all the memory it uses
949  */
delete_egraph_model(egraph_model_t * mdl)950 static void delete_egraph_model(egraph_model_t *mdl) {
951   safe_free(mdl->value);
952   mdl->value = NULL;
953   if (mdl->pstore != NULL) {
954     delete_pstore(mdl->pstore);
955     safe_free(mdl->pstore);
956     mdl->pstore = NULL;
957   }
958   if (mdl->fval_maker != NULL) {
959     delete_fresh_val_maker(mdl->fval_maker);
960     safe_free(mdl->fval_maker);
961     mdl->fval_maker = NULL;
962   }
963   delete_ivector(&mdl->root_classes);
964   delete_ivector(&mdl->rank_ctr);
965   q_clear(&mdl->arith_buffer);
966   delete_bvconstant(&mdl->bv_buffer);
967 }
968 
969 
970 /*
971  * Reset mdl: delete everything except the bv buffer
972  */
reset_egraph_model(egraph_model_t * mdl)973 static void reset_egraph_model(egraph_model_t *mdl) {
974   safe_free(mdl->value);
975   mdl->value = NULL;
976   if (mdl->pstore != NULL) {
977     delete_pstore(mdl->pstore);
978     safe_free(mdl->pstore);
979     mdl->pstore = NULL;
980   }
981   if (mdl->fval_maker != NULL) {
982     delete_fresh_val_maker(mdl->fval_maker);
983     safe_free(mdl->fval_maker);
984     mdl->fval_maker = NULL;
985   }
986   ivector_reset(&mdl->root_classes);
987   ivector_reset(&mdl->rank_ctr);
988   q_clear(&mdl->arith_buffer);
989 }
990 
991 
992 
993 
994 /***********************
995  *  ATOM CONSTRUCTION  *
996  **********************/
997 
998 /*
999  * Create atom <v, t> and add it to the core
1000  * - v must be a boolean variable in egraph->core, with no atom attached
1001  * - t must be a boolean term in egraph
1002  */
create_egraph_atom(egraph_t * egraph,bvar_t v,eterm_t t)1003 static void create_egraph_atom(egraph_t *egraph, bvar_t v, eterm_t t) {
1004   atom_t *atom;
1005   smt_core_t *core;
1006 
1007   core = egraph->core;
1008 
1009   assert(core != NULL && bvar_atom(core, v) == NULL);
1010 
1011   atom = (atom_t *) objstore_alloc(&egraph->atom_store);
1012   atom->eterm = t;
1013   atom->boolvar = v;
1014   atom->next = atom;
1015 
1016   attach_atom_to_bvar(core, v, tagged_egraph_atom(atom));
1017 
1018   egraph->natoms ++;
1019 }
1020 
1021 
1022 /*
1023  * Swap the successors of atom1 and atom2
1024  * - if they are in different circular list, this merge the two lists
1025  * - if they are in the same list, this splits it into two
1026  */
swap_next_atoms(atom_t * atom1,atom_t * atom2)1027 static inline void swap_next_atoms(atom_t *atom1, atom_t *atom2) {
1028   atom_t *aux;
1029 
1030   aux = atom1->next;
1031   atom1->next = atom2->next;
1032   atom2->next = aux;
1033 }
1034 
1035 
1036 /*
1037  * For debugging only: check whether two atom lists are equal or disjoint
1038  */
1039 #ifndef NDEBUG
1040 
1041 /*
1042  * Scan list starting from atom1, until either atom1 or atom2 is found
1043  */
scan_atom_list(atom_t * atom1,atom_t * atom2)1044 static atom_t *scan_atom_list(atom_t *atom1, atom_t *atom2) {
1045   atom_t *a;
1046   a = atom1;
1047   do {
1048     a = a->next;
1049   } while (a != atom1 && a != atom2);
1050 
1051   return a;
1052 }
1053 
disjoint_atom_lists(atom_t * atom1,atom_t * atom2)1054 static bool disjoint_atom_lists(atom_t *atom1, atom_t *atom2) {
1055   return scan_atom_list(atom1, atom2) == atom1;
1056 }
1057 
equal_atom_lists(atom_t * atom1,atom_t * atom2)1058 static bool equal_atom_lists(atom_t *atom1, atom_t *atom2) {
1059   return scan_atom_list(atom1, atom2) == atom2;
1060 }
1061 
1062 #endif
1063 
1064 
1065 /*
1066  * Aliases for swap_next_atoms
1067  */
merge_atom_lists(atom_t * atom1,atom_t * atom2)1068 static inline void merge_atom_lists(atom_t *atom1, atom_t *atom2) {
1069   assert(disjoint_atom_lists(atom1, atom2));
1070   swap_next_atoms(atom1, atom2);
1071 }
1072 
split_atom_lists(atom_t * atom1,atom_t * atom2)1073 static inline void split_atom_lists(atom_t *atom1, atom_t *atom2) {
1074   assert(equal_atom_lists(atom1, atom2));
1075   swap_next_atoms(atom1, atom2);
1076 }
1077 
1078 
1079 /*
1080  * Delete atom and remove it from the core.
1081  */
delete_egraph_atom(egraph_t * egraph,atom_t * atom)1082 static void delete_egraph_atom(egraph_t *egraph, atom_t *atom) {
1083   smt_core_t *core;
1084   bvar_t v;
1085 
1086   core = egraph->core;
1087   v = atom->boolvar;
1088 
1089   assert(core != NULL && bvar_atom(core, v) == tagged_egraph_atom(atom));
1090   assert(atom->next == atom);
1091 
1092   remove_bvar_atom(core, v);
1093   objstore_free(&egraph->atom_store, atom);
1094 
1095   assert(egraph->natoms > 0);
1096   egraph->natoms --;
1097 }
1098 
1099 
1100 /*
1101  * Get the egraph atom attached to a boolean variable v
1102  * return NULL if v has no atom or if the atom of v is not in an egraph atom
1103  */
get_egraph_atom_for_bvar(egraph_t * egraph,bvar_t v)1104 static atom_t *get_egraph_atom_for_bvar(egraph_t *egraph, bvar_t v) {
1105   smt_core_t *core;
1106   void *a;
1107 
1108   core = egraph->core;
1109   assert(core != NULL);
1110 
1111   a = bvar_atom(core, v);
1112   if (a != NULL && atom_tag(a) == EGRAPH_ATM_TAG) {
1113     return (atom_t *)a;
1114   }
1115   return NULL;
1116 }
1117 
1118 
1119 
1120 
1121 
1122 
1123 /************************
1124  *  TERM CONSTRUCTION   *
1125  ***********************/
1126 
1127 /*
1128  * Create a composite term
1129  */
new_composite_eterm(egraph_t * egraph,composite_t * cmp)1130 static eterm_t new_composite_eterm(egraph_t *egraph, composite_t *cmp) {
1131   eterm_t t;
1132   t = new_eterm(&egraph->terms, cmp);
1133   cmp->id = t;
1134   return t;
1135 }
1136 
new_apply(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a)1137 static eterm_t new_apply(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
1138   return new_composite_eterm(egraph, new_apply_composite(f, n, a));
1139 }
1140 
new_update(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a,occ_t v)1141 static eterm_t new_update(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
1142   return new_composite_eterm(egraph, new_update_composite(f, n, a, v));
1143 }
1144 
new_tuple(egraph_t * egraph,uint32_t n,occ_t * a)1145 static eterm_t new_tuple(egraph_t *egraph, uint32_t n, occ_t *a) {
1146   return new_composite_eterm(egraph, new_tuple_composite(n, a));
1147 }
1148 
new_ite(egraph_t * egraph,occ_t t1,occ_t t2,occ_t t3)1149 static eterm_t new_ite(egraph_t *egraph, occ_t t1, occ_t t2, occ_t t3) {
1150   return new_composite_eterm(egraph, new_ite_composite(t1, t2, t3));
1151 }
1152 
new_eq(egraph_t * egraph,occ_t t1,occ_t t2)1153 static eterm_t new_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
1154   return new_composite_eterm(egraph, new_eq_composite(t1, t2));
1155 }
1156 
new_or(egraph_t * egraph,uint32_t n,occ_t * a)1157 static eterm_t new_or(egraph_t *egraph, uint32_t n, occ_t *a) {
1158   return new_composite_eterm(egraph, new_or_composite(n, a));
1159 }
1160 
1161 // fails if too many distinct terms already exist (return null_eterm)
new_distinct(egraph_t * egraph,uint32_t n,occ_t * a)1162 static eterm_t new_distinct(egraph_t *egraph, uint32_t n, occ_t *a) {
1163   if (egraph->ndistincts >= MAX_DISTINCT_TERMS) {
1164     return null_eterm;
1165   }
1166   egraph->ndistincts ++;
1167 
1168   return new_composite_eterm(egraph, new_distinct_composite(n, a));
1169 }
1170 
new_lambda(egraph_t * egraph,occ_t t,int32_t tag)1171 static eterm_t new_lambda(egraph_t *egraph, occ_t t, int32_t tag) {
1172   return new_composite_eterm(egraph, new_lambda_composite(t, tag));
1173 }
1174 
1175 
1176 /*
1177  * HASH CONSING FOR COMPOSITES
1178  */
1179 
1180 /*
1181  * Hash-consing interface objects
1182  */
1183 typedef struct {
1184   int_hobj_t m;
1185   egraph_t *egraph;
1186   occ_t f;
1187   uint32_t n;
1188   occ_t *a;
1189 } apply_hobj_t;
1190 
1191 typedef struct {
1192   int_hobj_t m;
1193   egraph_t *egraph;
1194   occ_t f;
1195   uint32_t n;
1196   occ_t *a;
1197   occ_t v;
1198 } update_hobj_t;
1199 
1200 // hobj type used for tuple, distinct, and or
1201 typedef struct {
1202   int_hobj_t m;
1203   egraph_t *egraph;
1204   uint32_t n;
1205   occ_t *a;
1206 } composite_hobj_t;
1207 
1208 typedef struct {
1209   int_hobj_t m;
1210   egraph_t *egraph;
1211   occ_t t1, t2;
1212 } eq_hobj_t;
1213 
1214 typedef struct {
1215   int_hobj_t m;
1216   egraph_t *egraph;
1217   occ_t t1, t2, t3;
1218 } ite_hobj_t;
1219 
1220 typedef struct {
1221   int_hobj_t m;
1222   egraph_t *egraph;
1223   occ_t t;
1224   int32_t tag;
1225 } lambda_hobj_t;
1226 
1227 
1228 /*
1229  * Hash functions
1230  */
hash_apply_obj(apply_hobj_t * p)1231 static uint32_t hash_apply_obj(apply_hobj_t *p) {
1232   return hash_apply(p->f, p->n, p->a);
1233 }
1234 
hash_update_obj(update_hobj_t * p)1235 static uint32_t hash_update_obj(update_hobj_t *p) {
1236   return hash_update(p->f, p->n, p->a, p->v);
1237 }
1238 
hash_tuple_obj(composite_hobj_t * p)1239 static uint32_t hash_tuple_obj(composite_hobj_t *p) {
1240   return hash_tuple(p->n, p->a);
1241 }
1242 
hash_eq_obj(eq_hobj_t * p)1243 static uint32_t hash_eq_obj(eq_hobj_t *p) {
1244   return hash_eq(p->t1, p->t2);
1245 }
1246 
hash_ite_obj(ite_hobj_t * p)1247 static uint32_t hash_ite_obj(ite_hobj_t *p) {
1248   return hash_ite(p->t1, p->t2, p->t3);
1249 }
1250 
hash_distinct_obj(composite_hobj_t * p)1251 static uint32_t hash_distinct_obj(composite_hobj_t *p) {
1252   return hash_distinct(p->n, p->a);
1253 }
1254 
hash_or_obj(composite_hobj_t * p)1255 static uint32_t hash_or_obj(composite_hobj_t *p) {
1256   return hash_or(p->n, p->a);
1257 }
1258 
hash_lambda_obj(lambda_hobj_t * p)1259 static uint32_t hash_lambda_obj(lambda_hobj_t *p) {
1260   return hash_lambda(p->t, p->tag);
1261 }
1262 
1263 
1264 /*
1265  * Equality tests
1266  */
equal_apply_obj(apply_hobj_t * p,eterm_t i)1267 static bool equal_apply_obj(apply_hobj_t *p, eterm_t i) {
1268   composite_t *c;
1269 
1270   c = p->egraph->terms.body[i];
1271   assert(composite_body(c));
1272 
1273   return equal_apply(c, p->f, p->n, p->a);
1274 }
1275 
equal_update_obj(update_hobj_t * p,eterm_t i)1276 static bool equal_update_obj(update_hobj_t *p, eterm_t i) {
1277   composite_t *c;
1278 
1279   c = p->egraph->terms.body[i];
1280   assert(composite_body(c));
1281 
1282   return equal_update(c, p->f, p->n, p->a, p->v);
1283 }
1284 
equal_tuple_obj(composite_hobj_t * p,eterm_t i)1285 static bool equal_tuple_obj(composite_hobj_t *p, eterm_t i) {
1286   composite_t *c;
1287 
1288   c = p->egraph->terms.body[i];
1289   assert(composite_body(c));
1290 
1291   return equal_tuple(c, p->n, p->a);
1292 }
1293 
equal_eq_obj(eq_hobj_t * p,eterm_t i)1294 static bool equal_eq_obj(eq_hobj_t *p, eterm_t i) {
1295   composite_t *c;
1296 
1297   c = p->egraph->terms.body[i];
1298   assert(composite_body(c));
1299 
1300   return equal_eq(c, p->t1, p->t2);
1301 }
1302 
equal_ite_obj(ite_hobj_t * p,eterm_t i)1303 static bool equal_ite_obj(ite_hobj_t *p, eterm_t i) {
1304   composite_t *c;
1305 
1306   c = p->egraph->terms.body[i];
1307   assert(composite_body(c));
1308 
1309   return equal_ite(c, p->t1, p->t2, p->t3);
1310 }
1311 
equal_distinct_obj(composite_hobj_t * p,eterm_t i)1312 static bool equal_distinct_obj(composite_hobj_t *p, eterm_t i) {
1313   composite_t *c;
1314 
1315   c = p->egraph->terms.body[i];
1316   assert(composite_body(c));
1317 
1318   return equal_distinct(c, p->n, p->a);
1319 }
1320 
equal_or_obj(composite_hobj_t * p,eterm_t i)1321 static bool equal_or_obj(composite_hobj_t *p, eterm_t i) {
1322   composite_t *c;
1323 
1324   c = p->egraph->terms.body[i];
1325   assert(composite_body(c));
1326 
1327   return equal_or(c, p->n, p->a);
1328 }
1329 
equal_lambda_obj(lambda_hobj_t * p,eterm_t i)1330 static bool equal_lambda_obj(lambda_hobj_t *p, eterm_t i) {
1331   composite_t *c;
1332 
1333   c = p->egraph->terms.body[i];
1334   assert(composite_body(c));
1335 
1336   return equal_lambda(c, p->t, p->tag);
1337 }
1338 
1339 
1340 /*
1341  * Build functions
1342  */
build_apply_obj(apply_hobj_t * p)1343 static eterm_t build_apply_obj(apply_hobj_t *p) {
1344   return new_apply(p->egraph, p->f, p->n, p->a);
1345 }
1346 
build_update_obj(update_hobj_t * p)1347 static eterm_t build_update_obj(update_hobj_t *p) {
1348   return new_update(p->egraph, p->f, p->n, p->a, p->v);
1349 }
1350 
build_tuple_obj(composite_hobj_t * p)1351 static eterm_t build_tuple_obj(composite_hobj_t *p) {
1352   return new_tuple(p->egraph, p->n, p->a);
1353 }
1354 
build_eq_obj(eq_hobj_t * p)1355 static eterm_t build_eq_obj(eq_hobj_t *p) {
1356   return new_eq(p->egraph, p->t1, p->t2);
1357 }
1358 
build_ite_obj(ite_hobj_t * p)1359 static eterm_t build_ite_obj(ite_hobj_t *p) {
1360   return new_ite(p->egraph, p->t1, p->t2, p->t3);
1361 }
1362 
build_distinct_obj(composite_hobj_t * p)1363 static eterm_t build_distinct_obj(composite_hobj_t *p) {
1364   return new_distinct(p->egraph, p->n, p->a);
1365 }
1366 
build_or_obj(composite_hobj_t * p)1367 static eterm_t build_or_obj(composite_hobj_t *p) {
1368   return new_or(p->egraph, p->n, p->a);
1369 }
1370 
build_lambda_obj(lambda_hobj_t * p)1371 static eterm_t build_lambda_obj(lambda_hobj_t *p) {
1372   return new_lambda(p->egraph, p->t, p->tag);
1373 }
1374 
1375 
1376 /*
1377  * Hash-consing constructors
1378  */
egraph_apply_term(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a)1379 static eterm_t egraph_apply_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
1380   apply_hobj_t apply_hobj;
1381   apply_hobj.m.hash = (hobj_hash_t) hash_apply_obj;
1382   apply_hobj.m.eq = (hobj_eq_t) equal_apply_obj;
1383   apply_hobj.m.build = (hobj_build_t) build_apply_obj;
1384   apply_hobj.egraph = egraph;
1385   apply_hobj.f = f;
1386   apply_hobj.n = n;
1387   apply_hobj.a = a;
1388 
1389   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &apply_hobj);
1390 }
1391 
egraph_update_term(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a,occ_t v)1392 static eterm_t egraph_update_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
1393   update_hobj_t update_hobj;
1394   update_hobj.m.hash = (hobj_hash_t) hash_update_obj;
1395   update_hobj.m.eq = (hobj_eq_t) equal_update_obj;
1396   update_hobj.m.build = (hobj_build_t) build_update_obj;
1397   update_hobj.egraph = egraph;
1398   update_hobj.f = f;
1399   update_hobj.n = n;
1400   update_hobj.a = a;
1401   update_hobj.v = v;
1402 
1403   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &update_hobj);
1404 }
1405 
egraph_tuple_term(egraph_t * egraph,uint32_t n,occ_t * a)1406 static eterm_t egraph_tuple_term(egraph_t *egraph, uint32_t n, occ_t *a) {
1407   composite_hobj_t tuple_hobj;
1408   tuple_hobj.m.hash = (hobj_hash_t) hash_tuple_obj;
1409   tuple_hobj.m.eq = (hobj_eq_t) equal_tuple_obj;
1410   tuple_hobj.m.build = (hobj_build_t) build_tuple_obj;
1411   tuple_hobj.egraph = egraph;
1412   tuple_hobj.n = n;
1413   tuple_hobj.a = a;
1414 
1415   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &tuple_hobj);
1416 }
1417 
egraph_eq_term(egraph_t * egraph,occ_t t1,occ_t t2)1418 static eterm_t egraph_eq_term(egraph_t *egraph, occ_t t1, occ_t t2) {
1419   eq_hobj_t eq_hobj;
1420   eq_hobj.m.hash = (hobj_hash_t) hash_eq_obj;
1421   eq_hobj.m.eq = (hobj_eq_t) equal_eq_obj;
1422   eq_hobj.m.build = (hobj_build_t) build_eq_obj;
1423   eq_hobj.egraph = egraph;
1424   eq_hobj.t1 = t1;
1425   eq_hobj.t2 = t2;
1426 
1427   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &eq_hobj);
1428 }
1429 
egraph_ite_term(egraph_t * egraph,occ_t t1,occ_t t2,occ_t t3)1430 static eterm_t egraph_ite_term(egraph_t *egraph, occ_t t1, occ_t t2, occ_t t3) {
1431   ite_hobj_t ite_hobj;
1432   ite_hobj.m.hash = (hobj_hash_t) hash_ite_obj;
1433   ite_hobj.m.eq = (hobj_eq_t) equal_ite_obj;
1434   ite_hobj.m.build = (hobj_build_t) build_ite_obj;
1435   ite_hobj.egraph = egraph;
1436   ite_hobj.t1 = t1;
1437   ite_hobj.t2 = t2;
1438   ite_hobj.t3 = t3;
1439 
1440   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &ite_hobj);
1441 }
1442 
egraph_distinct_term(egraph_t * egraph,uint32_t n,occ_t * a)1443 static eterm_t egraph_distinct_term(egraph_t *egraph, uint32_t n, occ_t *a) {
1444   composite_hobj_t distinct_hobj;
1445 
1446   assert(n >= 3);
1447 
1448   distinct_hobj.m.hash = (hobj_hash_t) hash_distinct_obj;
1449   distinct_hobj.m.eq = (hobj_eq_t) equal_distinct_obj;
1450   distinct_hobj.m.build = (hobj_build_t) build_distinct_obj;
1451   distinct_hobj.egraph = egraph;
1452   distinct_hobj.n = n;
1453   distinct_hobj.a = a;
1454 
1455   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &distinct_hobj);
1456 }
1457 
egraph_or_term(egraph_t * egraph,uint32_t n,occ_t * a)1458 static eterm_t egraph_or_term(egraph_t *egraph, uint32_t n, occ_t *a) {
1459   composite_hobj_t or_hobj;
1460   or_hobj.m.hash = (hobj_hash_t) hash_or_obj;
1461   or_hobj.m.eq = (hobj_eq_t) equal_or_obj;
1462   or_hobj.m.build = (hobj_build_t) build_or_obj;
1463   or_hobj.egraph = egraph;
1464   or_hobj.n = n;
1465   or_hobj.a = a;
1466 
1467   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &or_hobj);
1468 }
1469 
egraph_lambda_term(egraph_t * egraph,occ_t t,int32_t tag)1470 static eterm_t egraph_lambda_term(egraph_t *egraph, occ_t t, int32_t tag) {
1471   lambda_hobj_t lambda_hobj;
1472   lambda_hobj.m.hash = (hobj_hash_t) hash_lambda_obj;
1473   lambda_hobj.m.eq = (hobj_eq_t) equal_lambda_obj;
1474   lambda_hobj.m.build = (hobj_build_t) build_lambda_obj;
1475   lambda_hobj.egraph = egraph;
1476   lambda_hobj.t = t;
1477   lambda_hobj.tag = tag;
1478 
1479   return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &lambda_hobj);
1480 }
1481 
1482 
1483 /*
1484  * Search whether a composite term already exists
1485  * - all functions return -1 (= null_eterm) if the term requested isn't present
1486  * - they return the eterm index otherwise
1487  */
egraph_find_apply_term(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a)1488 static eterm_t egraph_find_apply_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
1489   apply_hobj_t apply_hobj;
1490   apply_hobj.m.hash = (hobj_hash_t) hash_apply_obj;
1491   apply_hobj.m.eq = (hobj_eq_t) equal_apply_obj;
1492   apply_hobj.m.build = (hobj_build_t) build_apply_obj;
1493   apply_hobj.egraph = egraph;
1494   apply_hobj.f = f;
1495   apply_hobj.n = n;
1496   apply_hobj.a = a;
1497 
1498   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &apply_hobj);
1499 }
1500 
egraph_find_update_term(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a,occ_t v)1501 static eterm_t egraph_find_update_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
1502   update_hobj_t update_hobj;
1503   update_hobj.m.hash = (hobj_hash_t) hash_update_obj;
1504   update_hobj.m.eq = (hobj_eq_t) equal_update_obj;
1505   update_hobj.m.build = (hobj_build_t) build_update_obj;
1506   update_hobj.egraph = egraph;
1507   update_hobj.f = f;
1508   update_hobj.n = n;
1509   update_hobj.a = a;
1510   update_hobj.v = v;
1511 
1512   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &update_hobj);
1513 }
1514 
egraph_find_tuple_term(egraph_t * egraph,uint32_t n,occ_t * a)1515 static eterm_t egraph_find_tuple_term(egraph_t *egraph, uint32_t n, occ_t *a) {
1516   composite_hobj_t tuple_hobj;
1517   tuple_hobj.m.hash = (hobj_hash_t) hash_tuple_obj;
1518   tuple_hobj.m.eq = (hobj_eq_t) equal_tuple_obj;
1519   tuple_hobj.m.build = (hobj_build_t) build_tuple_obj;
1520   tuple_hobj.egraph = egraph;
1521   tuple_hobj.n = n;
1522   tuple_hobj.a = a;
1523 
1524   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &tuple_hobj);
1525 }
1526 
egraph_find_eq_term(egraph_t * egraph,occ_t t1,occ_t t2)1527 static eterm_t egraph_find_eq_term(egraph_t *egraph, occ_t t1, occ_t t2) {
1528   eq_hobj_t eq_hobj;
1529   eq_hobj.m.hash = (hobj_hash_t) hash_eq_obj;
1530   eq_hobj.m.eq = (hobj_eq_t) equal_eq_obj;
1531   eq_hobj.m.build = (hobj_build_t) build_eq_obj;
1532   eq_hobj.egraph = egraph;
1533   eq_hobj.t1 = t1;
1534   eq_hobj.t2 = t2;
1535 
1536   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &eq_hobj);
1537 }
1538 
egraph_find_ite_term(egraph_t * egraph,occ_t t1,occ_t t2,occ_t t3)1539 static eterm_t egraph_find_ite_term(egraph_t *egraph, occ_t t1, occ_t t2, occ_t t3) {
1540   ite_hobj_t ite_hobj;
1541   ite_hobj.m.hash = (hobj_hash_t) hash_ite_obj;
1542   ite_hobj.m.eq = (hobj_eq_t) equal_ite_obj;
1543   ite_hobj.m.build = (hobj_build_t) build_ite_obj;
1544   ite_hobj.egraph = egraph;
1545   ite_hobj.t1 = t1;
1546   ite_hobj.t2 = t2;
1547   ite_hobj.t3 = t3;
1548 
1549   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &ite_hobj);
1550 }
1551 
egraph_find_distinct_term(egraph_t * egraph,uint32_t n,occ_t * a)1552 static eterm_t egraph_find_distinct_term(egraph_t *egraph, uint32_t n, occ_t *a) {
1553   composite_hobj_t distinct_hobj;
1554 
1555   assert(n >= 3);
1556 
1557   distinct_hobj.m.hash = (hobj_hash_t) hash_distinct_obj;
1558   distinct_hobj.m.eq = (hobj_eq_t) equal_distinct_obj;
1559   distinct_hobj.m.build = (hobj_build_t) build_distinct_obj;
1560   distinct_hobj.egraph = egraph;
1561   distinct_hobj.n = n;
1562   distinct_hobj.a = a;
1563 
1564   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &distinct_hobj);
1565 }
1566 
egraph_find_or_term(egraph_t * egraph,uint32_t n,occ_t * a)1567 static eterm_t egraph_find_or_term(egraph_t *egraph, uint32_t n, occ_t *a) {
1568   composite_hobj_t or_hobj;
1569   or_hobj.m.hash = (hobj_hash_t) hash_or_obj;
1570   or_hobj.m.eq = (hobj_eq_t) equal_or_obj;
1571   or_hobj.m.build = (hobj_build_t) build_or_obj;
1572   or_hobj.egraph = egraph;
1573   or_hobj.n = n;
1574   or_hobj.a = a;
1575 
1576   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &or_hobj);
1577 }
1578 
egraph_find_lambda_term(egraph_t * egraph,occ_t t,int32_t tag)1579 static eterm_t egraph_find_lambda_term(egraph_t *egraph, occ_t t, int32_t tag) {
1580   lambda_hobj_t lambda_hobj;
1581   lambda_hobj.m.hash = (hobj_hash_t) hash_lambda_obj;
1582   lambda_hobj.m.eq = (hobj_eq_t) equal_lambda_obj;
1583   lambda_hobj.m.build = (hobj_build_t) build_lambda_obj;
1584   lambda_hobj.egraph = egraph;
1585   lambda_hobj.t = t;
1586   lambda_hobj.tag = tag;
1587 
1588   return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &lambda_hobj);
1589 }
1590 
1591 
1592 
1593 
1594 
1595 /*************************************
1596  *  HASH CONSING FOR CONSTANT TERMS  *
1597  ************************************/
1598 
1599 /*
1600  * Get the hash-table for constants: allocate it if needed.
1601  */
egraph_get_const_htbl(egraph_t * egraph)1602 static int_htbl_t *egraph_get_const_htbl(egraph_t *egraph) {
1603   int_htbl_t *tmp;
1604 
1605   tmp = egraph->const_htbl;
1606   if (tmp == NULL) {
1607     tmp = (int_htbl_t *) safe_malloc(sizeof(int_htbl_t));
1608     init_int_htbl(tmp, 0);
1609     egraph->const_htbl = tmp;
1610   }
1611 
1612   return tmp;
1613 }
1614 
1615 
1616 /*
1617  * Delete the hash-table for constants if it exists
1618  */
egraph_free_const_htbl(egraph_t * egraph)1619 static void egraph_free_const_htbl(egraph_t *egraph) {
1620   int_htbl_t *tmp;
1621 
1622   tmp = egraph->const_htbl;
1623   if (tmp != NULL) {
1624     delete_int_htbl(tmp);
1625     safe_free(tmp);
1626     egraph->const_htbl = NULL;
1627   }
1628 }
1629 
1630 
1631 /*
1632  * Hash consing object: a constant is defined by its type tau and its index id
1633  */
1634 typedef struct {
1635   int_hobj_t m;
1636   egraph_t *egraph;
1637   type_t tau;
1638   int32_t id;
1639 } const_hobj_t;
1640 
1641 
hash_constant(type_t tau,int32_t id)1642 static inline uint32_t hash_constant(type_t tau, int32_t id) {
1643   return jenkins_hash_pair(tau, id, 0x1889aed2);
1644 }
1645 
1646 // interface to the htbl
hash_const_hobj(const_hobj_t * p)1647 static uint32_t hash_const_hobj(const_hobj_t *p) {
1648   return hash_constant(p->tau, p->id);
1649 }
1650 
equal_const_hobj(const_hobj_t * p,eterm_t i)1651 static bool equal_const_hobj(const_hobj_t *p, eterm_t i) {
1652   eterm_table_t *terms;
1653 
1654   terms = &p->egraph->terms;
1655   return terms->real_type[i] == p->tau && constant_body_id(terms->body[i]) == p->id;
1656 }
1657 
1658 // build function: just create a new term with descriptor = constant(id)
1659 // the type must be set later, after a class is created
build_const_hobj(const_hobj_t * p)1660 static eterm_t build_const_hobj(const_hobj_t *p) {
1661   return new_eterm(&p->egraph->terms, mk_constant_body(p->id));
1662 }
1663 
1664 /*
1665  * Get the constant term defined by (tau, id):
1666  * - if that's a new term, the initialization is not complete yet
1667  */
egraph_constant_term(egraph_t * egraph,type_t tau,int32_t id)1668 static eterm_t egraph_constant_term(egraph_t *egraph, type_t tau, int32_t id) {
1669   int_htbl_t *const_htbl;
1670   const_hobj_t const_hobj;
1671 
1672   const_hobj.m.hash = (hobj_hash_t) hash_const_hobj;
1673   const_hobj.m.eq = (hobj_eq_t) equal_const_hobj;
1674   const_hobj.m.build = (hobj_build_t) build_const_hobj;
1675   const_hobj.egraph = egraph;
1676   const_hobj.tau = tau;
1677   const_hobj.id = id;
1678 
1679   const_htbl = egraph_get_const_htbl(egraph);
1680 
1681   return int_htbl_get_obj(const_htbl, (int_hobj_t *) &const_hobj);
1682 }
1683 
1684 
1685 /*
1686  * Remove the htbl record for constant term t
1687  */
egraph_delete_constant(egraph_t * egraph,eterm_t t)1688 static void egraph_delete_constant(egraph_t *egraph, eterm_t t) {
1689   type_t tau;
1690   int32_t id;
1691   uint32_t h;
1692 
1693   assert(egraph_term_is_constant(egraph, t) && egraph->const_htbl != NULL);
1694 
1695   tau = egraph_term_real_type(egraph, t);
1696   id = constant_body_id(egraph_term_body(egraph, t));
1697   h = hash_constant(tau, id);
1698   int_htbl_erase_record(egraph->const_htbl, h, t);
1699 }
1700 
1701 
1702 
1703 
1704 
1705 /**************************************************************
1706  *  SIMPLIFICATION OF COMPOSITES/SEARCH FOR CONGRUENCE ROOTS  *
1707  *************************************************************/
1708 
1709 /*
1710  * All analyze_xxx functions check whether a composite p simplifies or
1711  * is congruent to another composite q.
1712  * - if so, they add an equality to the propagation queue and return true
1713  * - otherwise they store p in the congruence table and use vectors,
1714  *   and return false
1715  */
1716 
1717 /*
1718  * Propagation of the form (t1 == t2) implies (p->id == x)
1719  */
add_eq_implies_eq(egraph_t * egraph,composite_t * p,occ_t x,occ_t t1,occ_t t2)1720 static inline void add_eq_implies_eq(egraph_t *egraph, composite_t *p, occ_t x, occ_t t1, occ_t t2) {
1721   int32_t k;
1722 
1723   // don't add anything if (p->id == x) already holds
1724   if (egraph_equal_occ(egraph, pos_occ(p->id), x)) return;
1725 
1726   k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), x);
1727   egraph->stack.etag[k] = EXPL_EQ;
1728   egraph->stack.edata[k].t[0] = t1;
1729   egraph->stack.edata[k].t[1] = t2;
1730 
1731 #if TRACE
1732   printf("---> EGRAPH: equality ");
1733   print_occurrence(stdout, pos_occ(p->id));
1734   printf(" == ");
1735   print_occurrence(stdout, x);
1736   printf(" implied by ");
1737   print_occurrence(stdout, t1);
1738   printf(" == ");
1739   print_occurrence(stdout, t2);
1740   printf("\n");
1741 #endif
1742 }
1743 
1744 
1745 /*
1746  * Propagation of the form (t1 != t2) implies (p->id == x), where t1 != t2 was derived from dmasks
1747  * dmsk must be dmask[class(t1)] & dmask[class(t2)]
1748  * The implied equality is always (p->id == false), where p is an equality term.
1749  */
add_diseq_implies_eq(egraph_t * egraph,composite_t * p,occ_t x,occ_t t1,occ_t t2,uint32_t dmsk)1750 static inline void add_diseq_implies_eq(egraph_t *egraph, composite_t *p, occ_t x,
1751                                         occ_t t1, occ_t t2, uint32_t dmsk) {
1752   int32_t k;
1753   uint32_t i;
1754 
1755   // don't add anything if (p->id == x) already holds
1756   if (egraph_equal_occ(egraph, pos_occ(p->id), x)) return;
1757 
1758   k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), x);
1759 
1760   // the tag depends on bit i of dmsk
1761   i = ctz(dmsk);
1762   assert(0 <= i && i < egraph->dtable.npreds);
1763   egraph->stack.etag[k] = (expl_tag_t) (i + EXPL_DISTINCT0);
1764   egraph->stack.edata[k].t[0] = t1;
1765   egraph->stack.edata[k].t[1] = t2;
1766 
1767 #if TRACE
1768   printf("---> EGRAPH: equality ");
1769   print_occurrence(stdout, pos_occ(p->id));
1770   printf(" == ");
1771   print_occurrence(stdout, x);
1772   printf(" implied by dmasks\n");
1773 #endif
1774 
1775 }
1776 
1777 
1778 
1779 /*
1780  * Basic terms: update/apply/tuple.
1781  * - no simplification rule is applied
1782  * - compute signature and look for a congruent term
1783  */
analyze_basic(egraph_t * egraph,composite_t * p)1784 static bool analyze_basic(egraph_t *egraph, composite_t *p) {
1785   composite_t *q;
1786   signature_t *sgn;
1787   elabel_t *label;
1788   int32_t k;
1789 
1790   label = egraph->terms.label;
1791   sgn = &egraph->sgn;
1792 
1793   signature_basic(p, label, sgn);
1794   q = congruence_table_get(&egraph->ctable, p, sgn, label);
1795   if (q != p) {
1796     // basic_congruence between p and q
1797     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
1798     egraph->stack.etag[k] = EXPL_BASIC_CONGRUENCE;
1799 #if TRACE
1800     printf("---> EGRAPH: equality ");
1801     print_occurrence(stdout, pos_occ(p->id));
1802     printf(" == ");
1803     print_occurrence(stdout, pos_occ(q->id));
1804     printf(" implied by congruence\n");
1805     printf("---> i.e., ");
1806     print_composite(stdout, p);
1807     printf(" == ");
1808     print_composite(stdout, q);
1809     printf("\n");
1810 #endif
1811     return true;
1812   }
1813 
1814   return false;
1815 }
1816 
1817 
1818 /*
1819  * p is (eq t1 t2)
1820  *
1821  * TODO?
1822  * add more simplifications for boolean equality:
1823  *   t1 == true  implies (eq t1 t2) == t2
1824  *   t1 == false implies (eq t1 t2) == (not t2)
1825  */
analyze_eq(egraph_t * egraph,composite_t * p)1826 static bool analyze_eq(egraph_t *egraph, composite_t *p) {
1827   occ_t t1, t2;
1828   elabel_t l1, l2;
1829   uint32_t dmsk;
1830   composite_t *q;
1831   signature_t *sgn;
1832   elabel_t *label;
1833   int32_t k;
1834 
1835   t1 = p->child[0];
1836   t2 = p->child[1];
1837   l1 = egraph_label(egraph, t1);
1838   l2 = egraph_label(egraph, t2);
1839 
1840   // t1 == t2 implies (eq t1 t2) == true
1841   if (l1 == l2) {
1842     add_eq_implies_eq(egraph, p, true_occ, t1, t2);
1843     return true;
1844   }
1845 
1846   // t1 == (not t2) implies (eq t1 t2) == false
1847   if (l1 == opposite_label(l2)) {
1848     add_eq_implies_eq(egraph, p, false_occ, t1, opposite_occ(t2));
1849     return true;
1850   }
1851 
1852   // t1 != t2 implies (eq t1 t2) == false
1853   dmsk = egraph->classes.dmask[class_of(l1)] & egraph->classes.dmask[class_of(l2)];
1854   if (dmsk != 0) {
1855     // note: the test (dmask[class_of(l1)] & dmask[class_of(l2)] != 0)
1856     // always fails if l1 and l2 are boolean
1857     add_diseq_implies_eq(egraph, p, false_occ, t1, t2, dmsk);
1858     return true;
1859   }
1860 
1861   // check for congruence
1862   label = egraph->terms.label;
1863   sgn = &egraph->sgn;
1864 
1865   signature_eq(p, label, sgn);
1866   q = congruence_table_get(&egraph->ctable, p, sgn, label);
1867   if (q != p) {
1868     // congruence
1869     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
1870     /*
1871      * EXPL_EQ_CONGRUENCE1 is the tag in two cases:
1872      * 1) t == u AND v == w IMPLIES (eq t v) == (eq u w)
1873      * 2) t == not u AND v == not w IMPLIES (eq t v) == (eq u w)
1874      *    where t, u, v, w are boolean terms
1875      */
1876     if (egraph_class(egraph, q->child[0]) == class_of(l1)) {
1877       egraph->stack.etag[k] = EXPL_EQ_CONGRUENCE1;
1878     } else {
1879       egraph->stack.etag[k] = EXPL_EQ_CONGRUENCE2;
1880     }
1881 #if TRACE
1882     printf("---> EGRAPH: equality ");
1883     print_occurrence(stdout, pos_occ(p->id));
1884     printf(" == ");
1885     print_occurrence(stdout, pos_occ(q->id));
1886     printf(" implied by eq congruence\n");
1887     printf("---> i.e., ");
1888     print_composite(stdout, p);
1889     printf(" == ");
1890     print_composite(stdout, q);
1891     printf("\n");
1892 #endif
1893     return true;
1894   }
1895 
1896   return false;
1897 }
1898 
1899 
1900 /*
1901  * p is (ite t1 t2 t3)
1902  */
analyze_ite(egraph_t * egraph,composite_t * p)1903 static bool analyze_ite(egraph_t *egraph, composite_t *p) {
1904   occ_t t1, t2, t3;
1905   elabel_t l1, l2, l3;
1906   composite_t *q;
1907   signature_t *sgn;
1908   elabel_t *label;
1909   int32_t k;
1910 
1911   t1 = p->child[0];
1912   t2 = p->child[1];
1913   t3 = p->child[2];
1914 
1915   l1 = egraph_label(egraph, t1);
1916 
1917   // t1 == true implies (ite t1 t2 t3) == t2
1918   if (l1 == true_label) {
1919     add_eq_implies_eq(egraph, p, t2, t1, true_occ);
1920     return true;
1921   }
1922 
1923   // t1 == false implies (ite t1 t2 t3) == t3
1924   if (l1 == false_label) {
1925     add_eq_implies_eq(egraph, p, t3, t1, false_occ);
1926     return true;
1927   }
1928 
1929   // t2 == t3 implies (ite t1 t2 t3) == t2
1930   l2 = egraph_label(egraph, t2);
1931   l3 = egraph_label(egraph, t3);
1932   if (l2 == l3) {
1933     add_eq_implies_eq(egraph, p, t2, t2, t3);
1934     return true;
1935   }
1936 
1937   // congruence check
1938   label = egraph->terms.label;
1939   sgn = &egraph->sgn;
1940 
1941   signature_ite(p, label, sgn);
1942   q = congruence_table_get(&egraph->ctable, p, sgn, label);
1943   if (q != p) {
1944     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
1945     if (egraph_label(egraph, q->child[0]) == l1) {
1946       egraph->stack.etag[k] = EXPL_ITE_CONGRUENCE1;
1947     } else {
1948       assert(egraph_label(egraph, q->child[0]) == opposite_label(l1));
1949       egraph->stack.etag[k] = EXPL_ITE_CONGRUENCE2;
1950     }
1951 #if TRACE
1952     printf("---> EGRAPH: equality ");
1953     print_occurrence(stdout, pos_occ(p->id));
1954     printf(" == ");
1955     print_occurrence(stdout, pos_occ(q->id));
1956     printf(" implied by ite congruence\n");
1957 #endif
1958     return true;
1959   }
1960 
1961   return false;
1962 }
1963 
1964 /*
1965  * p is (distinct t1 ... t_n)
1966  */
analyze_distinct(egraph_t * egraph,composite_t * p)1967 static bool analyze_distinct(egraph_t *egraph, composite_t *p) {
1968   composite_t *q;
1969   signature_t *sgn;
1970   elabel_t *label;
1971   uint32_t i, n;
1972   int32_t k;
1973 
1974   label = egraph->terms.label;
1975   sgn = &egraph->sgn;
1976   signature_distinct(p, label, sgn);
1977   // sgn = labels of t1 ... t_n in increasing order
1978 
1979   n = composite_arity(p);
1980   assert(tag_arity(sgn->tag) == n);
1981   for (i=0; i<n-1; i++) {
1982     // t_i == t_j implies (distinct t1 ... t_n) == false
1983     if (sgn->sigma[i] == sgn->sigma[i+1]) {
1984       k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), false_occ);
1985       gen_distinct_simpl_antecedent(egraph, p, sgn->sigma[i], k);
1986 #if TRACE
1987       printf("---> EGRAPH: distinct term ");
1988       print_occurrence(stdout, pos_occ(p->id));
1989       printf(" reduced to false because ");
1990       print_occurrence(stdout, egraph->stack.edata[k].t[0]);
1991       printf(" == ");
1992       print_occurrence(stdout, egraph->stack.edata[k].t[1]);
1993       printf("\n");
1994 #endif
1995       return true;
1996     }
1997   }
1998 
1999   // check for congruence
2000   q = congruence_table_get(&egraph->ctable, p, sgn, label);
2001   if (q != p) {
2002     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
2003     gen_distinct_congruence_antecedent(egraph, p, q, k);
2004 #if TRACE
2005     printf("---> EGRAPH: equality ");
2006     print_occurrence(stdout, pos_occ(p->id));
2007     printf(" == ");
2008     print_occurrence(stdout, pos_occ(q->id));
2009     printf(" implied by distinct congruence\n");
2010     printf("---> i.e., ");
2011     print_composite(stdout, p);
2012     printf(" == ");
2013     print_composite(stdout, q);
2014     printf("\n");
2015 #endif
2016     return true;
2017   }
2018 
2019   return false;
2020 }
2021 
2022 
2023 /*
2024  * p is (or t_1 ... t_n)
2025  */
find_child_label(egraph_t * egraph,composite_t * p,elabel_t x)2026 static occ_t find_child_label(egraph_t *egraph, composite_t *p, elabel_t x) {
2027   uint32_t i, n;
2028   occ_t t;
2029 
2030   n = composite_arity(p);
2031   for (i=0; i<n; i++) {
2032     t = p->child[i];
2033     if (egraph_label(egraph, t) == x) return t;
2034   }
2035   return null_occurrence;
2036 }
2037 
2038 
analyze_or(egraph_t * egraph,composite_t * p)2039 static bool analyze_or(egraph_t *egraph, composite_t *p) {
2040   composite_t *q;
2041   signature_t *sgn;
2042   elabel_t *label;
2043   uint32_t i, n;
2044   int32_t k;
2045   occ_t t, u;
2046 
2047   label = egraph->terms.label;
2048   sgn = &egraph->sgn;
2049   signature_or(p, label, sgn);
2050 
2051   // sgn = labels of t_1 ... t_n in increasing order
2052   // with duplicates and false_labels removed
2053   n = tag_arity(sgn->tag);
2054 
2055   if (n == 0) {
2056     // (or t_1 ... t_n) == false
2057     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), false_occ);
2058     egraph->stack.etag[k] = EXPL_SIMP_OR;
2059 #if TRACE
2060       printf("---> EGRAPH: or term ");
2061       print_occurrence(stdout, pos_occ(p->id));
2062       printf(" = ");
2063       print_composite(stdout, p);
2064       printf(" reduced to false\n");
2065 #endif
2066     return true;
2067   }
2068 
2069   // if one t_i == true then true_label is in sgn->sigma[0]
2070   if (sgn->sigma[0] == true_label) {
2071     t = find_child_label(egraph, p, true_label);
2072     assert(t >= 0);
2073     add_eq_implies_eq(egraph, p, true_occ, t, true_occ);
2074     return true;
2075   }
2076 
2077   if (n == 1) {
2078     // (or t_1 ... t_n) == t
2079     t = find_child_label(egraph, p, sgn->sigma[0]);
2080     assert(t >= 0);
2081     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), t);
2082     egraph->stack.etag[k] = EXPL_SIMP_OR;
2083 #if TRACE
2084       printf("---> EGRAPH: or term ");
2085       print_occurrence(stdout, pos_occ(p->id));
2086       printf(" = ");
2087       print_composite(stdout, p);
2088       printf(" reduced to ");
2089       print_occurrence(stdout, t);
2090       printf("\n");
2091 #endif
2092     return true;
2093   }
2094 
2095   // check for complementary labels
2096   for (i=1; i<n; i++) {
2097     if (sgn->sigma[i] == opposite_label(sgn->sigma[i-1])) {
2098       t = find_child_label(egraph, p, sgn->sigma[i]);
2099       u = find_child_label(egraph, p, sgn->sigma[i-1]);
2100       assert(t >= 0 && u >= 0);
2101       assert(egraph_label(egraph, u) == opposite_label(egraph_label(egraph, t)));
2102 
2103       // t == (not u) implies (or ... t ... u ...) == true
2104       add_eq_implies_eq(egraph, p, true_occ, t, opposite_occ(u));
2105 
2106       return true;
2107     }
2108   }
2109 
2110   // check for congruence
2111   q = congruence_table_get(&egraph->ctable, p, sgn, label);
2112   if (q != p) {
2113     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
2114     gen_or_congruence_antecedent(egraph, p, q, k);
2115 #if TRACE
2116     printf("---> EGRAPH: equality ");
2117     print_occurrence(stdout, pos_occ(p->id));
2118     printf(" == ");
2119     print_occurrence(stdout, pos_occ(q->id));
2120     printf(" implied by or congruence\n");
2121     printf("---> i.e., ");
2122     print_composite(stdout, p);
2123     printf(" == ");
2124     print_composite(stdout, q);
2125     printf("\n");
2126 #endif
2127     return true;
2128   }
2129 
2130   return false;
2131 }
2132 
2133 
2134 
2135 /*
2136  * p is (lambda c tag)
2137  */
analyze_lambda(egraph_t * egraph,composite_t * p)2138 static bool analyze_lambda(egraph_t *egraph, composite_t *p) {
2139   composite_t *q;
2140   signature_t *sgn;
2141   elabel_t *label;
2142   int32_t k;
2143 
2144   label = egraph->terms.label;
2145   sgn = &egraph->sgn;
2146 
2147   signature_lambda(p, label, sgn);
2148   q = congruence_table_get(&egraph->ctable, p, sgn, label);
2149   if (q != p) {
2150     // basic congruence
2151     k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
2152     egraph->stack.etag[k] = EXPL_BASIC_CONGRUENCE;
2153 #if TRACE
2154     printf("---> EGRAPH: equality ");
2155     print_occurrence(stdout, pos_occ(p->id));
2156     printf(" == ");
2157     print_occurrence(stdout, pos_occ(q->id));
2158     printf(" implied by lambda congruence\n");
2159     printf("---> i.e., ");
2160     print_composite(stdout, p);
2161     printf(" == ");
2162     print_composite(stdout, q);
2163     printf("\n");
2164 #endif
2165     return true;
2166   }
2167 
2168   return false;
2169 }
2170 
composite_simplifies(egraph_t * egraph,composite_t * p)2171 static bool composite_simplifies(egraph_t *egraph, composite_t *p) {
2172   switch (composite_kind(p)) {
2173   case COMPOSITE_APPLY:
2174   case COMPOSITE_UPDATE:
2175   case COMPOSITE_TUPLE:
2176     return analyze_basic(egraph, p);
2177 
2178   case COMPOSITE_EQ:
2179     return analyze_eq(egraph, p);
2180 
2181   case COMPOSITE_ITE:
2182     return analyze_ite(egraph, p);
2183 
2184   case COMPOSITE_DISTINCT:
2185     return analyze_distinct(egraph, p);
2186 
2187   case COMPOSITE_OR:
2188     return analyze_or(egraph, p);
2189 
2190   case COMPOSITE_LAMBDA:
2191     return analyze_lambda(egraph, p);
2192   }
2193 
2194   assert(false);
2195   return false;
2196 }
2197 
2198 
2199 
2200 
2201 /*********************
2202  *  TERM ACTIVATION  *
2203  ********************/
2204 
2205 /*
2206  * Check whether t is a newly created term (not active yet)
2207  */
egraph_term_is_fresh(egraph_t * egraph,eterm_t t)2208 static inline bool egraph_term_is_fresh(egraph_t *egraph, eterm_t t) {
2209   assert(0 <= t && t < egraph->terms.nterms);
2210   return egraph->terms.label[t] == null_label;
2211 }
2212 
2213 
2214 /*
2215  * Add composite d to the congruence table and use vectors
2216  * - if d is created at decision_level > 0 push d
2217  *   on the undo stack to be reanalyzed after backtracking.
2218  * - check whether t is equal to another term u and if so
2219  *   push the equality (t == u)
2220  */
egraph_activate_composite(egraph_t * egraph,composite_t * d)2221 static void egraph_activate_composite(egraph_t *egraph, composite_t *d) {
2222   undo_tag_t tag;
2223 
2224   assert(composite_body(d) && egraph->decision_level >= egraph->base_level);
2225 
2226   tag = REANALYZE_COMPOSITE;
2227 
2228   if (! composite_simplifies(egraph, d)) {
2229     /*
2230      * d is a congruence root
2231      * - composite_simplifies has added d to the congruence table
2232      * - we need to add it to the parent vectors
2233      */
2234     attach_composite(d, egraph->terms.label, egraph->classes.parents);
2235     tag = REANALYZE_CONGRUENCE_ROOT;
2236 
2237   }
2238 
2239   /*
2240    * If decision_level > base_level, we'll have to reanalyze d
2241    * after backtracking.
2242    *
2243    * If decision_level == base_level and base_level > 0, we'll also
2244    * have to reanalyze d on the next call to egraph_pop.  This will
2245    * force d to be removed from the parent vector and congruence table.
2246    *
2247    * We also have to do this if we're in reconcile_mode (since we may have to
2248    * backtrack and undo the provisional equalities added by model reconciliation).
2249    */
2250   if (egraph->decision_level > 0 || egraph->reconcile_mode) {
2251     undo_stack_push_ptr(&egraph->undo, d, tag);
2252   }
2253 }
2254 
2255 
2256 /*
2257  * Check whether theory variable x is a constant
2258  * - tau = egraph type for x
2259  */
constant_theory_var(egraph_t * egraph,etype_t tau,thvar_t x)2260 static bool constant_theory_var(egraph_t *egraph, etype_t tau, thvar_t x) {
2261   if (x != null_thvar) {
2262     switch (tau) {
2263     case ETYPE_INT:
2264     case ETYPE_REAL:
2265     case ETYPE_BV:
2266       return egraph->eg[tau]->is_constant(egraph->th[tau], x);
2267 
2268     default:
2269       break;
2270     }
2271   }
2272 
2273   return false;
2274 }
2275 
2276 
2277 /*
2278  * Attach variable x and type tau then activate term t:
2279  * - add t to a fresh singleton class c
2280  *
2281  * HACK: don't do a full activation for (distinct ...) terms
2282  * - it's enough to just add them to a singleton class.
2283  * - maintaining them into the congruence table and parent vectors
2284  *   is usually a waste of time.
2285  */
egraph_activate_term(egraph_t * egraph,eterm_t t,etype_t tau,thvar_t x)2286 static void egraph_activate_term(egraph_t *egraph, eterm_t t, etype_t tau, thvar_t x) {
2287   class_t c;
2288   composite_t *d;
2289   uint32_t dmask;
2290 
2291   assert(egraph_term_is_fresh(egraph, t));
2292 
2293   c = alloc_class(&egraph->classes);
2294   d = egraph->terms.body[t];
2295   egraph->terms.label[t] = pos_label(c);
2296   egraph->terms.thvar[t] = x;
2297 
2298   dmask = 0x0;
2299   if (constant_body(d) || constant_theory_var(egraph, tau, x)) {
2300     dmask = 0x1;
2301   }
2302   init_class(&egraph->classes, c, t, dmask, tau, x);
2303 
2304   if (composite_body(d) && composite_kind(d) != COMPOSITE_DISTINCT) {
2305     egraph_activate_composite(egraph, d);
2306   }
2307 }
2308 
2309 
2310 /*
2311  * Reactivate the terms in reanalyze_vector
2312  * - this must be called after backtracking and before processing any equality
2313  */
egraph_reactivate_dynamic_terms(egraph_t * egraph)2314 static void egraph_reactivate_dynamic_terms(egraph_t *egraph) {
2315   pvector_t *v;
2316   composite_t *p;
2317   uint32_t i, n;
2318 
2319   v = &egraph->reanalyze_vector;
2320   n = v->size;
2321   for (i=0; i<n; i++) {
2322     p = v->data[i];
2323     assert(composite_body(p));
2324     egraph_activate_composite(egraph, p);
2325   }
2326   pvector_reset(v);
2327 }
2328 
2329 
2330 
2331 
2332 
2333 /******************************************
2334  *  EQUALITY/DISTINCT/DISEQUALITY CHECKS  *
2335  *****************************************/
2336 
2337 /*
2338  * Check whether t1 and t2 are known to be disequal
2339  * Returns true in the following cases:
2340  * 1) t1 and (not t2) are equal
2341  * 2) there are distinct constants a1 and a2 with t1 == a1 and t2 == a2
2342  * 3) there's a term v = (eq u1 u2), such that v == false, and
2343  *     t1 == u1, t2 == u2 or t1 == u2, t2 == u1
2344  * 4) there's a term v = (distinct u_1 ... u_n) such that v == true,
2345  *    and t1 == u_i and t2 == u_j with i /= j
2346  * 5) t1 and t2 are attached to two theory variables x1 and x2,
2347  *    and the theory solver knows that x1 != x2
2348  */
egraph_check_diseq(egraph_t * egraph,occ_t t1,occ_t t2)2349 bool egraph_check_diseq(egraph_t *egraph, occ_t t1, occ_t t2) {
2350   uint32_t *dmask;
2351   composite_t *eq;
2352   class_t c1, c2;
2353 
2354   c1 = egraph_class(egraph, t1);
2355   c2 = egraph_class(egraph, t2);
2356 
2357   if (c1 == c2) {
2358     return polarity_of_occ(t1) != polarity_of_occ(t2);
2359   }
2360 
2361   dmask = egraph->classes.dmask;
2362   if ((dmask[c1] & dmask[c2]) != 0) {
2363     return true;
2364   }
2365 
2366   eq = congruence_table_find_eq(&egraph->ctable, t1, t2, egraph->terms.label);
2367   return eq != NULL_COMPOSITE && egraph_occ_is_false(egraph, pos_occ(eq->id));
2368 }
2369 
2370 
2371 /*
2372  * Check whether t1 and t2 are disequal via the theory solver
2373  * Return true if t1 and t2 are attached to two theory variables x1 and x2
2374  * and the corresponding theory solver knows that x1 and x2 are distinct.
2375  * - this looks at the base variables for t1 and t2
2376  */
egraph_check_theory_diseq(egraph_t * egraph,occ_t t1,occ_t t2)2377 bool egraph_check_theory_diseq(egraph_t *egraph, occ_t t1, occ_t t2) {
2378   etype_t i;
2379   thvar_t x1, x2;
2380 
2381   i = egraph_type(egraph, t1);
2382   switch (i) {
2383   case ETYPE_INT:
2384   case ETYPE_REAL:
2385   case ETYPE_BV:
2386   case ETYPE_FUNCTION:
2387     x1 = egraph_term_base_thvar(egraph, term_of_occ(t1));
2388     x2 = egraph_term_base_thvar(egraph, term_of_occ(t2));
2389     return x1 != null_thvar && x2 != null_thvar &&
2390       egraph->eg[i] != NULL &&
2391       egraph->eg[i]->check_diseq(egraph->th[i], x1, x2);
2392 
2393   default:
2394     return false;
2395   }
2396 }
2397 
2398 
2399 /*
2400  * Check whether d = (distinct u_1 ... u_n) is false.
2401  * Returns true if u_i == u_j for i/=j
2402  */
egraph_check_distinct_false(egraph_t * egraph,composite_t * d)2403 bool egraph_check_distinct_false(egraph_t *egraph, composite_t *d) {
2404   occ_t t;
2405   elabel_t x;
2406   uint32_t i, n;
2407   int_hmap_t *imap;
2408   int_hmap_pair_t *p;
2409   bool result;
2410 
2411   assert(composite_kind(d) == COMPOSITE_DISTINCT);
2412 
2413   n = composite_arity(d);
2414   result = false;
2415   imap = egraph_get_imap(egraph);
2416 
2417   for (i=0; i<n; i++) {
2418     t = d->child[i];
2419     x = egraph_label(egraph, t);
2420     p = int_hmap_get(imap, x);
2421     if (p->val >= 0) {
2422       result = true;
2423       break;
2424     }
2425     p->val = t;
2426   }
2427 
2428   int_hmap_reset(imap);
2429 
2430   return result;
2431 }
2432 
2433 
2434 /*
2435  * Check whether d = (distinct u_1 ... u_n) is true.
2436  * (Expensive).
2437  */
egraph_check_distinct_true(egraph_t * egraph,composite_t * d)2438 bool egraph_check_distinct_true(egraph_t *egraph, composite_t *d) {
2439   uint32_t i, j, n;
2440   occ_t x, y;
2441 
2442   assert(composite_kind(d) == COMPOSITE_DISTINCT);
2443   n = composite_arity(d);
2444 
2445   for (i=0; i<n; i++) {
2446     x = d->child[i];
2447     for (j=i+1; j<n; j++) {
2448       y = d->child[j];
2449       if (! egraph_check_diseq(egraph, x, y) && ! egraph_check_theory_diseq(egraph, x, y)) {
2450         return false;
2451       }
2452     }
2453   }
2454 
2455   return true;
2456 }
2457 
2458 
2459 /*
2460  * Incomplete but faster version
2461  */
egraph_fast_check_distinct_true(egraph_t * egraph,composite_t * d)2462 bool egraph_fast_check_distinct_true(egraph_t *egraph, composite_t *d) {
2463   uint32_t *dmask;
2464   uint32_t i, n, dmsk;
2465   occ_t x;
2466 
2467   assert(composite_kind(d) == COMPOSITE_DISTINCT);
2468 
2469   n = composite_arity(d);
2470   assert(n > 0);
2471 
2472   dmask = egraph->classes.dmask;
2473   dmsk = ~((uint32_t) 0);
2474   i = 0;
2475   do {
2476     x = d->child[i];
2477     dmsk &= dmask[egraph_class(egraph, x)];
2478     i ++;
2479   } while (dmsk != 0 && i < n);
2480 
2481   // dmsk trick does not rule out u_i == u_j
2482   return dmsk != 0 && ! egraph_check_distinct_false(egraph, d);
2483 }
2484 
2485 
2486 
2487 
2488 /*******************************************
2489  *   PREDICATE/BOOLEAN TERM CONSTRUCTORS   *
2490  ******************************************/
2491 
2492 #ifndef NDEBUG
2493 
2494 /*
2495  * For debugging: check whether (t == false) is in the assertion queue
2496  * - i.e., t was asserted to be false, but egraph_term_is_false(egraph, t)
2497  *   does not hold yet.
2498  */
egraph_term_asserted_false(egraph_t * egraph,eterm_t t)2499 static bool egraph_term_asserted_false(egraph_t *egraph, eterm_t t) {
2500   equeue_elem_t *e;
2501   uint32_t i, n;
2502   occ_t u;
2503 
2504   u = pos_occ(t);
2505 
2506   n = egraph->stack.top;
2507   for (i=egraph->stack.prop_ptr; i<n; i++) {
2508     e = egraph->stack.eq + i;
2509     if ((e->lhs == u && e->rhs == false_occ) ||
2510         (e->lhs == false_occ && e->rhs == u)) {
2511       return true;
2512     }
2513   }
2514 
2515   return false;
2516 }
2517 
2518 #endif
2519 
2520 
2521 /*
2522  * Atoms (type = BOOL, theory variable = a fresh boolean variable)
2523  * - all return pos_occ(theory_variable)
2524  * - make_pred build an uninterpreted predicate (f a[0] ... a[n])
2525  * - make_distinct rewrites (distinct a[0] ... a[n-1]) to a conjunction of
2526  *   disequalities if the distinct limit is reached.
2527  */
egraph_term2literal(egraph_t * egraph,eterm_t t)2528 static literal_t egraph_term2literal(egraph_t *egraph, eterm_t t) {
2529   bvar_t v;
2530 
2531   if (egraph_term_is_fresh(egraph, t)) {
2532     v = create_boolean_variable(egraph->core);
2533     create_egraph_atom(egraph, v, t);
2534     egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
2535     egraph_activate_term(egraph, t, ETYPE_BOOL, v);
2536   } else {
2537 #if CONSERVATIVE_DISEQ_AXIOMS
2538     v = egraph->terms.thvar[t];
2539     assert(v != null_thvar && egraph_term_type(egraph, t) == ETYPE_BOOL);
2540 #else
2541     /*
2542      * Hackish: this assumes that all existing boolean terms with no
2543      * theory variables attached are equalities asserted false (via
2544      * egraph_assert_diseq_axiom) at the base level.
2545      */
2546     assert(egraph_term_type(egraph, t) == ETYPE_BOOL);
2547     v = egraph->terms.thvar[t];
2548     if (v == null_thvar) {
2549       /*
2550        * This assertion is wrong: the equality t == false may not
2551        * be processed yet (i.e., still in the queue). If that's the
2552        * case, egraph_term_is_false(egraph, t) will return false and
2553        * the assertion will fail.
2554        */
2555       // assert(egraph_term_is_eq(egraph, t) && egraph_term_is_false(egraph, t));
2556       assert(egraph_term_is_eq(egraph, t));
2557       assert(egraph_term_is_false(egraph, t) || egraph_term_asserted_false(egraph, t));
2558 
2559       return false_literal;
2560     }
2561 #endif
2562   }
2563 
2564   return pos_lit(v);
2565 }
2566 
2567 
egraph_make_pred(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a)2568 literal_t egraph_make_pred(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
2569   eterm_t t;
2570   t = egraph_apply_term(egraph, f, n, a);
2571   return egraph_term2literal(egraph, t);
2572 }
2573 
2574 
egraph_make_eq(egraph_t * egraph,occ_t t1,occ_t t2)2575 literal_t egraph_make_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
2576   occ_t aux;
2577   eterm_t t;
2578 
2579   // simplify
2580   if (t1 == t2) return true_literal;
2581 
2582   /*
2583    * Careful: if we're in the reconcile_mode at the base level
2584    * we can't check for equality/disequality here using egraph_equal_occ or
2585    * egraph_check_diseq. That's because there may be tentative equalities
2586    * in the egraph at this point (so egraph_equal_occ and egraph_check_diseq
2587    * may give incorrect results).
2588    *
2589    * The test for reconcile_mode was missing. Bug reported by Martin Gabris.
2590    */
2591   //  if (egraph->base_level == egraph->decision_level) {
2592   if (egraph->base_level == egraph->decision_level
2593       && (! egraph->reconcile_mode || egraph->stack.top == egraph->reconcile_neqs)) {
2594     if (egraph_equal_occ(egraph, t1, t2)) {
2595       return true_literal;
2596     } else if (egraph_check_diseq(egraph, t1, t2)) {
2597       return false_literal;
2598     }
2599   }
2600 
2601   if (egraph_check_theory_diseq(egraph, t1, t2)) {
2602     // should work at any decision level
2603     return false_literal;
2604   }
2605 
2606   // normalize
2607   if (t1 > t2) {
2608     aux = t1; t1 = t2; t2 = aux;
2609   }
2610 
2611   t = egraph_eq_term(egraph, t1, t2);
2612   return egraph_term2literal(egraph, t);
2613 }
2614 
2615 
2616 #if ! CONSERVATIVE_DISEQ_AXIOMS
2617 
2618 /*
2619  * Variant of make_eq used by assert_diseq_axiom:
2620  * create a term but not the attached atom or literal
2621  */
egraph_make_eq_term(egraph_t * egraph,occ_t t1,occ_t t2)2622 static occ_t egraph_make_eq_term(egraph_t *egraph, occ_t t1, occ_t t2) {
2623   occ_t aux;
2624   eterm_t t;
2625 
2626   // simplify
2627   if (t1 == t2) return true_occ;
2628 
2629   if (egraph->base_level == egraph->decision_level) {
2630     if (egraph_equal_occ(egraph, t1, t2)) {
2631       return true_occ;
2632     } else if (egraph_check_diseq(egraph, t1, t2) || egraph_check_theory_diseq(egraph, t1, t2)) {
2633       return false_occ;
2634     }
2635   }
2636 
2637   // normalize
2638   if (t1 > t2) {
2639     aux = t1; t1 = t2; t2 = aux;
2640   }
2641 
2642   t = egraph_eq_term(egraph, t1, t2);
2643   if (egraph_term_is_fresh(egraph, t)) {
2644     egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
2645     egraph_activate_term(egraph, t, ETYPE_BOOL, null_thvar);
2646   }
2647   return pos_occ(t);
2648 }
2649 
2650 #endif
2651 
2652 /*
2653  * Generate all equalities (a[i] == a[j]) for 0 <= i < j <n
2654  * - the result is stored as literals in vector *v
2655  */
expand_distinct(egraph_t * egraph,uint32_t n,occ_t * a,ivector_t * v)2656 static void expand_distinct(egraph_t *egraph, uint32_t n, occ_t *a, ivector_t *v) {
2657   uint32_t i, j;
2658   occ_t a_i;
2659   literal_t l;
2660 
2661   ivector_reset(v);
2662   for (i=0; i<n-1; i++) {
2663     a_i = a[i];
2664     for (j=i+1; j<n; j++) {
2665       l = egraph_make_eq(egraph, a_i, a[j]);
2666       ivector_push(v, l);
2667     }
2668   }
2669 }
2670 
2671 /*
2672  * Create a fresh boolean variable x and assert clauses equivalent to
2673  * - not(x) == (distinct a[0] ... a[n-1])
2674  */
assert_distinct_def_clauses(egraph_t * egraph,uint32_t n,occ_t * a)2675 static literal_t assert_distinct_def_clauses(egraph_t *egraph, uint32_t n, occ_t *a) {
2676   ivector_t *v;
2677   literal_t l;
2678   uint32_t i, p;
2679   smt_core_t *core;
2680 
2681   v = &egraph->aux_buffer;
2682   expand_distinct(egraph, n, a, v);
2683   core = egraph->core;
2684   assert(core != NULL);
2685   l = pos_lit(create_boolean_variable(core));
2686 
2687   // clauses for pos_lit(x) == (or (eq a[0] a[1]) .... (eq a[n-1] a[n]))
2688   p = v->size;
2689   for (i=0; i<p; i++) {
2690     add_binary_clause(core, l, not(v->data[i]));
2691   }
2692   ivector_push(v, not(l));
2693   add_clause(core, p+1, v->data);
2694 
2695   return not(l);
2696 }
2697 
2698 
egraph_make_distinct(egraph_t * egraph,uint32_t n,occ_t * a)2699 literal_t egraph_make_distinct(egraph_t *egraph, uint32_t n, occ_t *a) {
2700   eterm_t t;
2701 
2702   /*
2703    * TODO: check this:
2704    * 1) normalize the term t?
2705    * 2) always expand small distinct terms?
2706    */
2707   t = egraph_distinct_term(egraph, n, a);
2708   if (t == null_eterm) {
2709     return assert_distinct_def_clauses(egraph, n, a);
2710   } else {
2711     return egraph_term2literal(egraph, t);
2712   }
2713 }
2714 
2715 
2716 
2717 
2718 /*
2719  * Boolean if-then-else
2720  */
egraph_make_boolean_ite(egraph_t * egraph,occ_t c,occ_t t1,occ_t t2)2721 literal_t egraph_make_boolean_ite(egraph_t *egraph, occ_t c, occ_t t1, occ_t t2) {
2722   eterm_t t;
2723 
2724   if (is_pos_occ(c)) {
2725     t = egraph_ite_term(egraph, c, t1, t2);
2726   } else {
2727     t = egraph_ite_term(egraph, opposite_occ(c), t2, t1);
2728   }
2729   return egraph_term2literal(egraph, t);
2730 }
2731 
2732 
2733 /*
2734  * OR term
2735  */
egraph_make_or(egraph_t * egraph,uint32_t n,occ_t * a)2736 literal_t egraph_make_or(egraph_t *egraph, uint32_t n, occ_t *a) {
2737   eterm_t t;
2738 
2739   t = egraph_or_term(egraph, n, a);
2740   return egraph_term2literal(egraph, t);
2741 }
2742 
2743 
2744 
2745 
2746 
2747 /****************************************
2748  *  TEST WHETHER COMPOSITE TERMS EXIST  *
2749  ***************************************/
2750 
egraph_apply_exists(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a)2751 bool egraph_apply_exists(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
2752   return egraph_find_apply_term(egraph, f, n, a) >= 0;
2753 }
2754 
egraph_ite_exists(egraph_t * egraph,occ_t c,occ_t t1,occ_t t2)2755 bool egraph_ite_exists(egraph_t *egraph, occ_t c, occ_t t1, occ_t t2) {
2756   if (is_pos_occ(c)) {
2757     return egraph_find_ite_term(egraph, c, t1, t2) >= 0;
2758   } else {
2759     return egraph_find_ite_term(egraph, opposite_occ(c), t2, t1) >= 0;
2760   }
2761 }
2762 
egraph_update_exists(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a,occ_t v)2763 bool egraph_update_exists(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
2764   return egraph_find_update_term(egraph, f, n, a, v) >= 0;
2765 }
2766 
egraph_tuple_exists(egraph_t * egraph,uint32_t n,occ_t * a)2767 bool egraph_tuple_exists(egraph_t *egraph, uint32_t n, occ_t *a) {
2768   return egraph_find_tuple_term(egraph, n, a) >= 0;
2769 }
2770 
egraph_eq_exists(egraph_t * egraph,occ_t t1,occ_t t2)2771 bool egraph_eq_exists(egraph_t *egraph, occ_t t1, occ_t t2) {
2772   if (t1 < t2) {
2773     return egraph_find_eq_term(egraph, t1, t2) >= 0;
2774   } else {
2775     return egraph_find_eq_term(egraph, t2, t1) >= 0;
2776   }
2777 }
2778 
egraph_distinct_exists(egraph_t * egraph,uint32_t n,occ_t * a)2779 bool egraph_distinct_exists(egraph_t *egraph, uint32_t n, occ_t *a) {
2780   return egraph_find_distinct_term(egraph, n, a) >= 0;
2781 }
2782 
egraph_or_exists(egraph_t * egraph,uint32_t n,occ_t * a)2783 bool egraph_or_exists(egraph_t *egraph, uint32_t n, occ_t *a) {
2784   return egraph_find_or_term(egraph, n, a) >= 0;
2785 }
2786 
2787 
egraph_lambda_exists(egraph_t * egraph,occ_t t,type_t tau)2788 bool egraph_lambda_exists(egraph_t *egraph, occ_t t, type_t tau) {
2789   int32_t tag;
2790 
2791   tag = find_lambda_tag_for_type(&egraph->tag_table, egraph->types, tau);
2792   return tag >= 0 && egraph_find_lambda_term(egraph, t, tag);
2793 }
2794 
2795 
2796 
2797 /**********************************
2798  *  APPLY/UPDATE SIMPLIFICATIONS  *
2799  *********************************/
2800 
2801 /*
2802  * Check whether (a[0], ..., a[n-1]) != (b[0],...,b[n-1]) holds at the base level
2803  */
egraph_check_diseq_arrays(egraph_t * egraph,uint32_t n,occ_t * a,occ_t * b)2804 static bool egraph_check_diseq_arrays(egraph_t *egraph, uint32_t n, occ_t *a, occ_t *b) {
2805   uint32_t i;
2806 
2807   for (i=0; i<n; i++) {
2808     if (egraph_check_diseq(egraph, a[i], b[i]) || egraph_check_theory_diseq(egraph, a[i], b[i])) {
2809       return true;
2810     }
2811   }
2812   return false;
2813 }
2814 
2815 
2816 /*
2817  * Check whether (a[0] ... a[n-1]) == (b[0] ... b[n-1]) at the current level
2818  */
egraph_check_eq_arrays(egraph_t * egraph,uint32_t n,occ_t * a,occ_t * b)2819 static bool egraph_check_eq_arrays(egraph_t *egraph, uint32_t n, occ_t *a, occ_t *b) {
2820   uint32_t i;
2821 
2822   for (i=0; i<n; i++) {
2823     if (! egraph_check_eq(egraph, a[i], b[i])) {
2824       return false;
2825     }
2826   }
2827   return true;
2828 }
2829 
2830 
2831 static void auto_activate(egraph_t *egraph, eterm_t u, type_t type);
2832 
2833 /*
2834  * Check whether (apply f a[0] ... a[n-1]) is reducible
2835  * to an existing term occurrence u.
2836  * - return null_occurrence if nothing is found
2837  */
egraph_reduce_apply(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a)2838 static occ_t egraph_reduce_apply(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
2839   composite_t *cmp;
2840   eterm_t t;
2841   occ_t g;
2842 
2843   g = f;
2844   assert(is_pos_occ(g));
2845   cmp = egraph_term_body(egraph, term_of_occ(g));
2846   while (composite_body(cmp) && composite_kind(cmp) == COMPOSITE_UPDATE) {
2847     assert(composite_arity(cmp) == n + 2);
2848     // g is (update h b[0] .. b[n-1] v)
2849     if (egraph_check_diseq_arrays(egraph, n, cmp->child + 1, a)) {
2850       // (apply g a[0] ... a[n-1]) --> (apply h a[0] ... a[n-1])
2851       g = composite_child(cmp, 0); // g := h
2852       assert(is_pos_occ(g));
2853       cmp = egraph_term_body(egraph, term_of_occ(g));
2854     } else if (egraph_check_eq_arrays(egraph, n, cmp->child + 1, a)) {
2855       // (apply g a[0] ... a[n-1]) --> v
2856       return composite_child(cmp, n+1);
2857     } else {
2858       if (g != f) {
2859         // (apply f a[0] ... a[n-1]) == (apply g a[0] ... a[n-1])
2860         // so we return (apply g a[0] ... a[n-1]).
2861         t = egraph_apply_term(egraph, g, n, a);
2862         if (egraph_term_is_fresh(egraph, t)) {
2863           type_t tau;
2864 
2865           tau = egraph_term_real_type(egraph, term_of_occ(g));
2866           tau = function_type_range(egraph->types, tau);
2867           auto_activate(egraph, t, tau);
2868         }
2869         return pos_occ(t);
2870       }
2871       break;
2872     }
2873   }
2874 
2875   return null_occurrence;
2876 }
2877 
2878 
2879 
2880 
2881 
2882 /******************************************
2883  *   CONSTRUCTORS FOR NON-BOOLEAN TERMS   *
2884  *****************************************/
2885 
2886 /*
2887  * Conversion from a type tau in the type table to an egraph type
2888  */
2889 static const uint8_t type_kind2etype[NUM_TYPE_KINDS] = {
2890   ETYPE_NONE,     // UNUSED_TYPE (should not occur)
2891   ETYPE_BOOL,     // BOOL_TYPE
2892   ETYPE_INT,      // INT_TYPE
2893   ETYPE_REAL,     // REAL_TYPE
2894   ETYPE_BV,       // BITVECTOR_TYPE
2895   ETYPE_NONE,     // SCALAR_TYPE
2896   ETYPE_NONE,     // UNINTERPRETED_TYPE
2897   ETYPE_NONE,     // VARIABLE_TYPE (should not occur)
2898   ETYPE_TUPLE,    // TUPLE_TYPE
2899   ETYPE_FUNCTION, // FUNCTION_TYPE
2900   ETYPE_NONE,     // INSTANCE_TYPE
2901 };
2902 
type_to_etype(type_table_t * types,type_t tau)2903 static inline etype_t type_to_etype(type_table_t *types, type_t tau) {
2904   return (etype_t) type_kind2etype[type_kind(types, tau)];
2905 }
2906 
2907 
2908 /*
2909  * Activate egraph term u and attach an adequate theory variable to u
2910  * - type = type for u
2911  */
auto_activate(egraph_t * egraph,eterm_t u,type_t type)2912 static void auto_activate(egraph_t *egraph, eterm_t u, type_t type) {
2913   etype_t tau;
2914   thvar_t x;
2915   uint32_t n;
2916 
2917   assert(egraph_term_is_fresh(egraph, u));
2918 
2919   /*
2920    * To ensure that attach_eterm is called last:
2921    * 1) create a theory variable x
2922    * 2) activate the term u
2923    * 3) attach u to x in the satellite solver
2924    */
2925   tau = type_to_etype(egraph->types, type);
2926   x = null_thvar;
2927   switch (tau) {
2928   case ETYPE_INT:
2929     if (egraph->arith_smt != NULL) {
2930       x = egraph->arith_eg->create_arith_var(egraph->th[ETYPE_INT], true);
2931     }
2932     break;
2933 
2934   case ETYPE_REAL:
2935     if (egraph->arith_smt != NULL) {
2936       x = egraph->arith_eg->create_arith_var(egraph->th[ETYPE_REAL], false);
2937     }
2938     break;
2939 
2940   case ETYPE_BV:
2941     if (egraph->bv_smt != NULL) {
2942       n = bv_type_size(egraph->types, type);
2943       x = egraph->bv_eg->create_bv_var(egraph->th[ETYPE_BV], n);
2944     }
2945     break;
2946 
2947   case ETYPE_FUNCTION:
2948     if (egraph->ctrl[ETYPE_FUNCTION] != NULL) {
2949       x = egraph->fun_eg->create_fun_var(egraph->th[ETYPE_FUNCTION], type);
2950     }
2951     break;
2952 
2953   case ETYPE_NONE:
2954     // no theory variable
2955     break;
2956 
2957   case ETYPE_TUPLE:
2958     // if u is a tuple term, theory variable = the term itself
2959     if (egraph_term_is_composite_tuple(egraph, u)) {
2960       x = u;
2961     }
2962     break;
2963 
2964   case ETYPE_BOOL:
2965     x = create_boolean_variable(egraph->core);
2966     create_egraph_atom(egraph, x, u);
2967     break;
2968 
2969   default:
2970     assert(false);
2971     abort();
2972   }
2973 
2974   // set the term type and activate it
2975   egraph_set_term_real_type(egraph, u, type);
2976   egraph_activate_term(egraph, u, tau, x);
2977 
2978   // attach u to x in the satellite solver
2979   if (tau <= ETYPE_FUNCTION && egraph->eg[tau] != NULL) {
2980     egraph->eg[tau]->attach_eterm(egraph->th[tau], x, u);
2981   }
2982 
2983 }
2984 
2985 
2986 /*
2987  * Create the constant of type tau and index id
2988  * - id = same index as the matching constant in the term table
2989  */
egraph_make_constant(egraph_t * egraph,type_t tau,int32_t id)2990 eterm_t egraph_make_constant(egraph_t *egraph, type_t tau, int32_t id) {
2991   eterm_t t;
2992 
2993   t = egraph_constant_term(egraph, tau, id);
2994   if (egraph_term_is_fresh(egraph, t)) {
2995     egraph_set_term_real_type(egraph, t, tau);
2996     egraph_activate_term(egraph, t, ETYPE_NONE, null_thvar);
2997   }
2998 
2999   return t;
3000 }
3001 
3002 
3003 /*
3004  * If-then-else of type tau
3005  */
egraph_make_ite(egraph_t * egraph,occ_t c,occ_t t1,occ_t t2,type_t tau)3006 eterm_t egraph_make_ite(egraph_t *egraph, occ_t c, occ_t t1, occ_t t2, type_t tau) {
3007   eterm_t t;
3008 
3009   if (is_pos_occ(c)) {
3010     t = egraph_ite_term(egraph, c, t1, t2);
3011   } else {
3012     t = egraph_ite_term(egraph, opposite_occ(c), t2, t1);
3013   }
3014 
3015   if (egraph_term_is_fresh(egraph, t)) {
3016     auto_activate(egraph, t, tau);
3017   }
3018   return t;
3019 }
3020 
3021 
3022 /*
3023  * Update of type tau
3024  */
egraph_make_update(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a,occ_t v,type_t tau)3025 eterm_t egraph_make_update(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v, type_t tau) {
3026   composite_t *cmp;
3027   eterm_t t;
3028 
3029   assert(is_pos_occ(f));
3030 
3031   /*
3032    * simplification: remove double updates at the same indices:
3033    * rewrite (update (update f x a) x b) to (update f x b)
3034    */
3035   cmp = egraph_term_body(egraph, term_of_occ(f));
3036   if (composite_body(cmp) && composite_kind(cmp) == COMPOSITE_UPDATE &&
3037       egraph_check_eq_arrays(egraph, n, cmp->child + 1, a)) {
3038     f = cmp->child[0];
3039     assert(is_pos_occ(f));
3040   }
3041 
3042   /*
3043    * Simplification 2: (update f x (f x)) is f
3044    */
3045   cmp = egraph_term_body(egraph, term_of_occ(v));
3046   if (is_pos_occ(v) && composite_body(cmp) &&
3047       composite_kind(cmp) == COMPOSITE_APPLY &&
3048       cmp->child[0] == f &&  egraph_check_eq_arrays(egraph, n, cmp->child + 1, a)) {
3049     return term_of_occ(f);
3050   }
3051 
3052   t = egraph_update_term(egraph, f, n, a, v);
3053   if (egraph_term_is_fresh(egraph, t)) {
3054     auto_activate(egraph, t, tau);
3055   }
3056   return t;
3057 }
3058 
3059 
3060 /*
3061  * Tuples: (type = tau, etype = TUPLE, theory variable = itself)
3062  * - the term's body is (tuple a[0], .., a[n-1])
3063  */
egraph_make_tuple(egraph_t * egraph,uint32_t n,occ_t * a,type_t tau)3064 eterm_t egraph_make_tuple(egraph_t *egraph, uint32_t n, occ_t *a, type_t tau) {
3065   eterm_t t;
3066 
3067   t = egraph_tuple_term(egraph, n, a);
3068   if (egraph_term_is_fresh(egraph, t)) {
3069     auto_activate(egraph, t, tau);
3070   }
3071   return t;
3072 }
3073 
3074 
3075 /*
3076  * Constant lambda term (lambda ... c)
3077  * - tau must be a function type
3078  * - attach a theory variable in the array solver (if present)
3079  */
egraph_make_lambda(egraph_t * egraph,occ_t c,type_t tau)3080 eterm_t egraph_make_lambda(egraph_t *egraph, occ_t c, type_t tau) {
3081   eterm_t t;
3082   int32_t tag;
3083 
3084   tag = lambda_tag_for_type(&egraph->tag_table, egraph->types, tau);
3085   t = egraph_lambda_term(egraph, c, tag);
3086   if (egraph_term_is_fresh(egraph, t)) {
3087     auto_activate(egraph, t, tau);
3088   }
3089 
3090   return t;
3091 }
3092 
3093 
3094 /*
3095  * TYPE CONSTRAINTS
3096  */
3097 
3098 /*
3099  * Axiom for term occurrence t of scalar type tau
3100  */
egraph_add_scalar_axiom(egraph_t * egraph,occ_t t,type_t tau)3101 static void egraph_add_scalar_axiom(egraph_t *egraph, occ_t t, type_t tau) {
3102   uint32_t i, n;
3103   occ_t k;
3104   ivector_t *v;
3105 
3106   n = scalar_type_cardinal(egraph->types, tau);
3107   v = &egraph->aux_buffer;
3108   ivector_reset(v);
3109 
3110   for (i=0; i<n; i++) {
3111     k = pos_occ(egraph_make_constant(egraph, tau, i));
3112     ivector_push(v, egraph_make_eq(egraph, t, k));
3113   }
3114   assert(v->size == n);
3115 
3116   add_clause(egraph->core, n, v->data);
3117 }
3118 
3119 
3120 /*
3121  * Skolem term for type tau:
3122  * - if tau is atomic, return a fresh variable of type tau
3123  * - if tau is a tuple type, return (tuple x_1 ... x_n)
3124  *   where x_1 ... x_n are recursive skolem terms for tau's component
3125  */
egraph_skolem_term(egraph_t * egraph,type_t tau)3126 eterm_t egraph_skolem_term(egraph_t *egraph, type_t tau) {
3127   tuple_type_t *d;
3128   occ_t *a;
3129   eterm_t t;
3130   uint32_t i, n;
3131 
3132   switch (type_kind(egraph->types, tau)) {
3133   case TUPLE_TYPE:
3134     d = tuple_type_desc(egraph->types, tau);
3135     n = d->nelem;
3136     a = alloc_istack_array(&egraph->istack, n);
3137     for (i=0; i<n; i++) {
3138       a[i] = pos_occ(egraph_skolem_term(egraph, d->elem[i]));
3139     }
3140     t = egraph_make_tuple(egraph, n, a, tau);
3141     free_istack_array(&egraph->istack, a);
3142     break;
3143 
3144   default:
3145     t = egraph_make_variable(egraph, tau);
3146     break;
3147   }
3148 
3149   return t;
3150 }
3151 
3152 
3153 /*
3154  * Type constraints for a fresh term t of type tau
3155  */
egraph_add_type_constraints(egraph_t * egraph,eterm_t t,type_t tau)3156 static void egraph_add_type_constraints(egraph_t *egraph, eterm_t t, type_t tau) {
3157   occ_t sk;
3158   literal_t l;
3159   int32_t k;
3160 
3161   switch (type_kind(egraph->types, tau)) {
3162   case SCALAR_TYPE:
3163     egraph_add_scalar_axiom(egraph, pos_occ(t), tau);
3164     break;
3165 
3166   case TUPLE_TYPE:
3167     sk = pos_occ(egraph_skolem_term(egraph, tau));
3168     if (egraph->presearch) {
3169       // before start search: assert the axiom directly
3170       assert(egraph->decision_level == egraph->base_level);
3171       k = egraph_stack_push_eq(&egraph->stack, pos_occ(t), sk);
3172       egraph->stack.etag[k] = EXPL_AXIOM;
3173     } else {
3174       /*
3175        * Add a unit clause in the core.
3176        *
3177        * IMPORTANT: we can't add an equality axiom directly
3178        * (even if decision_level == base_level), because
3179        * any equality pushed into egraph->stack may be removed
3180        * (in final_check).
3181        */
3182       l = egraph_make_eq(egraph, pos_occ(t), sk);
3183       add_unit_clause(egraph->core, l);
3184     }
3185     break;
3186 
3187   default:
3188     break;
3189   }
3190 }
3191 
3192 /*
3193  * Create a fresh variable of type tau
3194  */
egraph_make_variable(egraph_t * egraph,type_t tau)3195 eterm_t egraph_make_variable(egraph_t *egraph, type_t tau) {
3196   eterm_t t;
3197 
3198   t = new_eterm(&egraph->terms, VARIABLE_BODY);
3199   auto_activate(egraph, t, tau);
3200   egraph_add_type_constraints(egraph, t, tau);
3201   return t;
3202 }
3203 
3204 
3205 /*
3206  * Create a function application of type tau
3207  */
egraph_make_apply(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a,type_t tau)3208 eterm_t egraph_make_apply(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, type_t tau) {
3209   eterm_t t;
3210   occ_t u;
3211   int32_t k;
3212 
3213   t = egraph_apply_term(egraph, f, n, a);
3214   if (egraph_term_is_fresh(egraph, t)) {
3215     auto_activate(egraph, t, tau);
3216     egraph_add_type_constraints(egraph, t, tau);
3217     if (egraph->presearch) {
3218       assert(egraph->decision_level == egraph->base_level);
3219       // check for apply/update reduction
3220       u = egraph_reduce_apply(egraph, f, n, a);
3221       if (u != null_occurrence) {
3222         // add (t == u) as an axiom
3223         k = egraph_stack_push_eq(&egraph->stack, pos_occ(t), u);
3224         egraph->stack.etag[k] = EXPL_AXIOM;
3225         egraph->stats.app_reductions ++;
3226       }
3227     }
3228   }
3229   return t;
3230 }
3231 
3232 
3233 
3234 
3235 /***************
3236  *  UTILITIES  *
3237  **************/
3238 
3239 /*
3240  * Search for a tuple-term u such that u == t
3241  * - return null_eterm if there is none
3242  */
egraph_get_tuple_in_class(egraph_t * egraph,eterm_t t)3243 eterm_t egraph_get_tuple_in_class(egraph_t *egraph, eterm_t t) {
3244   eterm_t tv;
3245   class_t c;
3246 
3247   c = egraph_term_class(egraph, t);
3248   assert(egraph_class_is_tuple(egraph, c));
3249   tv = egraph_class_thvar(egraph, c);
3250 
3251 #ifndef NDEBUG
3252   if (tv != null_eterm) {
3253     composite_t *cmp;
3254     cmp = egraph_term_body(egraph, tv);
3255     assert(composite_body(cmp) && cmp != NULL && composite_kind(cmp) == COMPOSITE_TUPLE);
3256   }
3257 #endif
3258 
3259   return tv;
3260 }
3261 
3262 
3263 /*
3264  * Return a term t equal to boolean variable v
3265  * - search for an egraph atom of the form <t, v>
3266  * - if there is one return t
3267  * - otherwise, create a fresh term t (variable + BOOL type)
3268  *   and construct the atom <t, v>
3269  * - if v already has a non-egraph atom attached,
3270  *   then we create a fresh v', assert v' == v in the core then
3271  *   attach t to v'
3272  *
3273  * BUG FIX: 2017/05/16: We also create a fresh v' and assert v' == v
3274  * if the variable v is already assigned. This makes sure that the
3275  * egraph will be notified that v' is true or false on the next call
3276  * to propagate, and turn that into t==true or t==false.
3277  *
3278  *
3279  * If a new term is created, it is activated.
3280  */
egraph_bvar2term(egraph_t * egraph,bvar_t v)3281 eterm_t egraph_bvar2term(egraph_t *egraph, bvar_t v) {
3282   void *atom;
3283   bvar_t aux;
3284   eterm_t t;
3285   smt_core_t *core;
3286 
3287   core = egraph->core;
3288   assert(core != NULL);
3289 
3290   atom = bvar_atom(core, v);
3291   if (atom != NULL && atom_tag(atom) == EGRAPH_ATM_TAG) {
3292     return ((atom_t *) atom)->eterm;
3293   }
3294 
3295   if (atom != NULL || bvar_is_assigned(core, v)) {
3296     /*
3297      * Either v is attached for an atom outisde the egraph
3298      * or v is already assigned. In this case, we replace v by a fresh
3299      * variable and assert aux == v in the core.
3300      */
3301     aux = v;
3302     v = create_boolean_variable(core);
3303     // assert aux <=> v
3304     add_binary_clause(core, pos_lit(v), neg_lit(aux));
3305     add_binary_clause(core, neg_lit(v), pos_lit(aux));
3306   }
3307 
3308   // create fresh t + new atom  <t, v>
3309   t = new_eterm(&egraph->terms, VARIABLE_BODY);
3310   create_egraph_atom(egraph, v, t);
3311   egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
3312   egraph_activate_term(egraph, t, ETYPE_BOOL, v);
3313 
3314   return t;
3315 }
3316 
3317 
3318 
3319 
3320 /*
3321  * Return a term t of type tau equal to theory variable v
3322  * - t is a fresh egraph variable
3323  * - v must not be attached to another term t'
3324  * - there must be a theory solver for the type tau
3325  */
egraph_thvar2term(egraph_t * egraph,thvar_t v,type_t tau)3326 eterm_t egraph_thvar2term(egraph_t *egraph, thvar_t v, type_t tau) {
3327   etype_t eta;
3328   eterm_t t;
3329 
3330   eta = type_to_etype(egraph->types, tau);
3331   assert(eta <= ETYPE_FUNCTION && egraph->eg[eta] != NULL);
3332 
3333   // fresh variable
3334   t = new_eterm(&egraph->terms, VARIABLE_BODY);
3335 
3336   // set the term type and activate t
3337   egraph_set_term_real_type(egraph, t, tau);
3338   egraph_activate_term(egraph, t, eta, v);
3339 
3340   // attach t to v in the satellite solver
3341   egraph->eg[eta]->attach_eterm(egraph->th[eta], v, t);
3342 
3343   return t;
3344 }
3345 
3346 
3347 /*
3348  * Create the built-in boolean constant
3349  */
egraph_init_constant(egraph_t * egraph)3350 static void egraph_init_constant(egraph_t *egraph) {
3351   eterm_t t0;
3352 
3353   t0 = new_eterm(&egraph->terms, mk_constant_body(0));
3354   assert(t0 == true_eterm);
3355   create_egraph_atom(egraph, const_bvar, t0);
3356   egraph_set_term_real_type(egraph, t0, bool_type(egraph->types));
3357   egraph_activate_term(egraph, t0, ETYPE_BOOL, const_bvar);
3358 }
3359 
3360 
3361 
3362 
3363 /**************************
3364  *  AUXILIARY EQUALITIES  *
3365  *************************/
3366 
3367 /*
3368  * Auxiliary equalities are created when adding ackermann lemmas.
3369  * To prevent blow up, we put a limit on the number of auxiliary
3370  * equalities created. When the limit is reached, creation of
3371  * new auxiliary fails. Only lemmas that are built from existing
3372  * equalities can be added at that point.
3373  * - the quota is stored in egraph->aux_eq_quota
3374  * - the number of auxiliary equalities created is in egraph->stats.aux_eqs
3375  */
3376 
3377 /*
3378  * Variant build function for auxiliary equalities
3379  */
build_aux_eq_obj(eq_hobj_t * p)3380 static eterm_t build_aux_eq_obj(eq_hobj_t *p) {
3381   egraph_t *g;
3382 
3383   g = p->egraph;
3384   if (g->stats.aux_eqs >= g->aux_eq_quota) {
3385     return null_eterm;
3386   }
3387   g->stats.aux_eqs ++;
3388   return new_eq(g, p->t1, p->t2);
3389 }
3390 
3391 /*
3392  * Constructor for auxiliary equality:
3393  * - returns null_literal if the construction fails (i.e., when the quota is reached)
3394  */
egraph_make_aux_eq(egraph_t * egraph,occ_t t1,occ_t t2)3395 static literal_t egraph_make_aux_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
3396   occ_t aux;
3397   eterm_t t;
3398   eq_hobj_t aux_eq_hobj;
3399 
3400   if (t1 == t2) return true_literal;
3401 
3402   if (t1 > t2) {
3403     // normalize
3404     aux = t1; t1 = t2; t2 = aux;
3405   }
3406 
3407   // call hash-consing constructor
3408   aux_eq_hobj.m.hash = (hobj_hash_t) hash_eq_obj;
3409   aux_eq_hobj.m.eq = (hobj_eq_t) equal_eq_obj;
3410   aux_eq_hobj.m.build =(hobj_build_t) build_aux_eq_obj ;
3411   aux_eq_hobj.egraph = egraph;
3412   aux_eq_hobj.t1 = t1;
3413   aux_eq_hobj.t2 = t2;
3414   t = int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &aux_eq_hobj);
3415 
3416   if (t == null_eterm) {
3417     return null_literal;  // quota exceeded
3418   } else {
3419     return egraph_term2literal(egraph, t);
3420   }
3421 }
3422 
3423 
3424 
3425 
3426 /************************
3427  *  LEMMA CONSTRUCTION  *
3428  ***********************/
3429 
3430 /*
3431  * Distinct expansion: add the lemma
3432  *  ((distinct t_1 ... t_n) or (eq t_1 t_2) .... or (eq t_n-1 t_n))
3433  * where d = (distinct t_1 ... t_n)
3434  */
create_distinct_lemma(egraph_t * egraph,composite_t * d)3435 static void create_distinct_lemma(egraph_t *egraph, composite_t *d) {
3436   bvar_t x;
3437   eterm_t t;
3438   ivector_t *v;
3439   cache_elem_t *e;
3440 
3441   assert(composite_kind(d) == COMPOSITE_DISTINCT);
3442 
3443   // check the cache first
3444   t = d->id;
3445   e = cache_get(&egraph->cache, DISTINCT_LEMMA, t, null_eterm);
3446   if (e->flag == NEW_CACHE_ELEM) {
3447     // lemma not previously expanded
3448     e->flag ++;
3449 
3450     // create the clause
3451     v = &egraph->aux_buffer;
3452     expand_distinct(egraph, composite_arity(d), d->child, v);
3453 
3454     x = egraph->terms.thvar[t];
3455     ivector_push(v, pos_lit(x));
3456     add_clause(egraph->core, v->size, v->data);
3457 
3458     // update statistics
3459     egraph->stats.nd_lemmas ++;
3460   }
3461 }
3462 
3463 
3464 /*
3465  * Get cache element for ackermann lemma (t1, t2)
3466  */
cache_get_ackermann_lemma(cache_t * cache,eterm_t t1,eterm_t t2)3467 static cache_elem_t *cache_get_ackermann_lemma(cache_t *cache, eterm_t t1, eterm_t t2) {
3468   eterm_t aux;
3469 
3470   if (t1 > t2) {
3471     aux = t1; t1 = t2; t2 = aux;
3472   }
3473   return cache_get(cache, ACKERMANN_LEMMA, t1, t2);
3474 }
3475 
3476 
3477 /*
3478  * Ackermann lemma: add the lemma
3479  *   (eq t_1 u_1) ... (eq t_n u_n) IMPLIES (eq (f t_1 ... t_n) (f u_1 ... u_n))
3480  * - c1 = (f t_1 ... t_n)
3481  * - c2 = (f u_1 ... u_n)
3482  */
create_ackermann_lemma(egraph_t * egraph,composite_t * c1,composite_t * c2)3483 static void create_ackermann_lemma(egraph_t *egraph, composite_t *c1, composite_t *c2) {
3484   uint32_t i, n;
3485   ivector_t *v;
3486   cache_elem_t *e;
3487   literal_t l;
3488   eterm_t b1, b2;
3489   thvar_t x1, x2;
3490 
3491   assert(composite_kind(c1) == composite_kind(c2) && composite_arity(c1) == composite_arity(c2));
3492 
3493   b1 = c1->id;
3494   b2 = c2->id;
3495 
3496   if (egraph_term_type(egraph, b1) == ETYPE_BOOL) {
3497     assert(egraph_term_type(egraph, b2) == ETYPE_BOOL);
3498 
3499     if (egraph_option_enabled(egraph, EGRAPH_DYNAMIC_BOOLACKERMANN) &&
3500         egraph->stats.boolack_lemmas < egraph->max_boolackermann) {
3501 
3502       /*
3503        * (f t_1 ... t_n) and (f u_1 ... u_n) are boolean.
3504        * Find boolean variables
3505        *   x1 <==> (f t_1 ... t_n) and x2 <==> (f u_1 ... u_n)
3506        * Add two clause:
3507        *  (eq t_1 u_1) AND ... AND (eq t_n u_n) AND x1 ==> x2
3508        *  (eq t_1 u_1) AND ... AND (eq t_n u_n) AND x2 ==> x1
3509        *
3510        * Before generating the clauses, check the number of hits for
3511        * the pair (b1, b2). Add the clauses if this reaches
3512        * boolack_threshold.
3513        */
3514       e = cache_get_ackermann_lemma(&egraph->cache, b1, b2);
3515       if (e->flag < egraph->boolack_threshold) {
3516         e->flag ++;
3517         if (e->flag == egraph->boolack_threshold) {
3518           x1 = egraph_term_base_thvar(egraph, b1);
3519           x2 = egraph_term_base_thvar(egraph, b2);
3520           if (x1 != null_thvar && x2 != null_thvar) {
3521             // generate the clause
3522             v = &egraph->aux_buffer;
3523             ivector_reset(v);
3524             n = composite_arity(c1);
3525             for (i=0; i<n; i++) {
3526               l = egraph_make_aux_eq(egraph, c1->child[i], c2->child[i]);
3527               if (l == null_literal) return; // quota exceeded: fail
3528               if (l != true_literal) {
3529                 ivector_push(v, not(l));
3530               }
3531             }
3532             i = v->size;
3533             // add x1 ==> x2
3534             ivector_push(v, neg_lit(x1));
3535             ivector_push(v, pos_lit(x2));
3536             add_clause(egraph->core, v->size, v->data);
3537             // add x2 ==> x1
3538             v->data[i] = neg_lit(x2);
3539             v->data[i+1] = pos_lit(x1);
3540             add_clause(egraph->core, v->size, v->data);
3541 
3542             egraph->stats.boolack_lemmas ++;
3543           }
3544         }
3545       }
3546     }
3547 
3548   } else {
3549 
3550     if (egraph_option_enabled(egraph, EGRAPH_DYNAMIC_ACKERMANN) &&
3551         egraph->stats.ack_lemmas < egraph->max_ackermann) {
3552 
3553       /*
3554        * Non-boolean case: add the clause
3555        * (t_1 == u_1 and ... and t_n == u_n) ==>
3556        *                (f t_1 .. t_n) == (f u_1 ... u_n)
3557        *
3558        * Generate the lemma if the number of hits for (b1, b2)
3559        * reaches ackermann_threshold.
3560        */
3561       e = cache_get_ackermann_lemma(&egraph->cache, b1, b2);
3562       if (e->flag < egraph->ackermann_threshold) {
3563         e->flag ++;
3564         if (e->flag == egraph->ackermann_threshold) {
3565           v = &egraph->aux_buffer;
3566           ivector_reset(v);
3567           n = composite_arity(c1);
3568           for (i=0; i<n; i++) {
3569             l = egraph_make_aux_eq(egraph, c1->child[i], c2->child[i]);
3570             if (l == null_literal) return; // aux_eq_quota exceeded
3571             if (l != true_literal) {
3572               ivector_push(v, not(l));
3573             }
3574           }
3575           l = egraph_make_eq(egraph, pos_occ(b1), pos_occ(b2));
3576           ivector_push(v, l);
3577 
3578 #if 0
3579           printf("---> ackermann lemma[%"PRIu32"]:\n", egraph->stats.ack_lemmas + 1);
3580           n = v->size;
3581           assert(n > 0);
3582           if (n > 1) {
3583             printf("(or ");
3584           }
3585           for (i=0; i<n; i++) {
3586             printf(" ");
3587             print_egraph_atom_of_literal(stdout, egraph, v->data[i]);
3588           }
3589           if (n > 1) {
3590             printf(")");
3591           }
3592           printf("\n");
3593           printf("      ");
3594           print_eterm_def(stdout, egraph,  c1->id);
3595           printf("      ");
3596           print_eterm_def(stdout, egraph,  c2->id);
3597           fflush(stdout);
3598 #endif
3599 
3600           add_clause(egraph->core, v->size, v->data);
3601 
3602           // update statistics
3603           egraph->stats.ack_lemmas ++;
3604         }
3605       }
3606     }
3607   }
3608 }
3609 
3610 
3611 
3612 
3613 /*********************************************************
3614  *  EQUALITY AND DISEQUALITIES BETWEEN THEORY VARIABLES  *
3615  ********************************************************/
3616 
3617 /*
3618  * Propagate equality between two theory variables v1 and v2 in theory i
3619  * - v1 = theory var of c1
3620  * - v2 = theory var of c2
3621  * - id = edge index that caused v1 and v2 to be merged (must be stored by the
3622  *   theory solver to pass it to egraph_explain_equality).
3623  * This is called when c1 and c2 are merged
3624  * - c1 remains root (and v1 remains visible in the egraph)
3625  * - c2 is no longer root after the merge (so v2 is no longer
3626  *   visible in the egraph).
3627  */
propagate_satellite_equality(egraph_t * egraph,etype_t i,thvar_t v1,thvar_t v2,int32_t id)3628 static void propagate_satellite_equality(egraph_t *egraph, etype_t i, thvar_t v1, thvar_t v2, int32_t id) {
3629   assert(i < NUM_SATELLITES && egraph->eg[i] != NULL);
3630 
3631   // call the merge function for theory i
3632   egraph->eg[i]->assert_equality(egraph->th[i], v1, v2, id);
3633 }
3634 
3635 
3636 /*
3637  * Propagate disequality between v1 and v2 in theory i
3638  */
propagate_satellite_disequality(egraph_t * egraph,etype_t i,thvar_t v1,thvar_t v2,composite_t * hint)3639 static void propagate_satellite_disequality(egraph_t *egraph, etype_t i, thvar_t v1, thvar_t v2, composite_t *hint) {
3640   assert(i < NUM_SATELLITES && egraph->eg[i] != NULL);
3641   egraph->eg[i]->assert_disequality(egraph->th[i], v1, v2, hint);
3642 }
3643 
3644 
3645 /*
3646  * Propagate (distinct a[0] ... a[n-1]) to satellite solver i
3647  * - each a[k] is a theory variable in that solver
3648  * - hint is a composite term that implies (distinct a[0] ... a[n-1]):
3649  *   hint is (distinct t_0 ... t_p-1) asserted true,
3650  *   and each a[i] is a theory variable attached to the class of some term t_j
3651  */
propagate_satellite_distinct(egraph_t * egraph,etype_t i,uint32_t n,thvar_t * a,composite_t * hint)3652 static void propagate_satellite_distinct(egraph_t *egraph, etype_t i, uint32_t n, thvar_t *a, composite_t *hint) {
3653   assert(i < NUM_SATELLITES && egraph->eg[i] != NULL);
3654   egraph->eg[i]->assert_distinct(egraph->th[i], n, a, hint);
3655 }
3656 
3657 
3658 /*
3659  * EQUALITIES BETWEEN TUPLES AND BETWEEN BOOLEAN VARIABLES
3660  */
3661 
3662 /*
3663  * Tuple-equality propagation: implement the rule
3664  * (tuple t_1 ... t_n) == (tuple u_1 ... u_n) implies t_i == u_i
3665  * - v1: term with body[v1] = (tuple t_1 ... t_n)
3666  * - v2: term with body[v2] = (tuple u_1 ... u_n)
3667  */
propagate_tuple_equality(egraph_t * egraph,eterm_t v1,eterm_t v2)3668 static void propagate_tuple_equality(egraph_t *egraph, eterm_t v1, eterm_t v2) {
3669   composite_t *p1, *p2;
3670   uint32_t i, n;
3671   occ_t x1, x2;
3672   int32_t k;
3673 
3674   p1 = egraph_term_body(egraph, v1);
3675   p2 = egraph_term_body(egraph, v2);
3676 
3677   // if input is type correct, then p1 and p2 must have same arity
3678   // so p1->tag == p2->tag
3679   assert(composite_body(p1) && composite_body(p2) && p1->tag == p2->tag
3680          && composite_kind(p1) == COMPOSITE_TUPLE);
3681 
3682   assert(egraph_equal_occ(egraph, pos_occ(v1), pos_occ(v2)));
3683 
3684   n = composite_arity(p1);
3685   x1 = pos_occ(v1);
3686   x2 = pos_occ(v2);
3687   for (i=0; i<n; i++) {
3688     if (! egraph_equal_occ(egraph, p1->child[i], p2->child[i])) {
3689       // (x1 == x2) implies p1->child[i] == p2->child[i]
3690       k = egraph_stack_push_eq(&egraph->stack, p1->child[i], p2->child[i]);
3691       egraph->stack.etag[k] = EXPL_EQ;
3692       egraph->stack.edata[k].t[0] = x1;
3693       egraph->stack.edata[k].t[1] = x2;
3694     }
3695   }
3696 }
3697 
3698 
3699 /*
3700  * When boolean variable v1 and v2 are merged into the same boolean class
3701  * - this means that either v1 == v2 or v1 == (not v2)
3702  * - if v1 == const_bvar, then v2 is now true or false.
3703  * - id = edge index that caused v1 and v2 to be merged
3704  *
3705  * Special case: if v1 is const_bvar then v2 may also be const_bvar
3706  * - that's because we use const_bvar as theory variable for (distinct .. ) axioms
3707  *   so different classes may be mapped to const_bvar.
3708  */
propagate_boolean_equality(egraph_t * egraph,bvar_t v1,bvar_t v2,int32_t id)3709 static void propagate_boolean_equality(egraph_t *egraph, bvar_t v1, bvar_t v2, int32_t id) {
3710   atom_t *atm1, *atm2, *atm;
3711   smt_core_t *core;
3712   literal_t l;
3713 
3714   core = egraph->core;
3715   assert(core != NULL && bvar_has_atom(core, v1) && bvar_has_atom(core, v2));
3716 
3717   atm1 = get_bvar_atom(core, v1);
3718   atm2 = get_bvar_atom(core, v2);
3719 
3720   if (v1 == const_bvar) {
3721     atm = atm2;
3722     do {
3723       /*
3724        * atm->eterm is either true or false
3725        * assign the same value to atm->boolvar
3726        * we keep track of the edge id in the antecedent of atm->boolvar
3727        * in the core.
3728        */
3729       assert(egraph_term_is_true(egraph, atm->eterm) ||
3730              egraph_term_is_false(egraph, atm->eterm));
3731 
3732       if (bvar_is_unassigned(core, atm->boolvar)) {
3733         l = mk_lit(atm->boolvar, egraph_term_is_false(egraph, atm->eterm));
3734         propagate_literal(core, l, mk_i32_expl(id));
3735         egraph->stats.th_props ++;
3736       }
3737 
3738       atm = atm->next;
3739 
3740     } while (atm != atm2);
3741   }
3742 
3743   merge_atom_lists(atm1, atm2);
3744 }
3745 
3746 
3747 
3748 /*
3749  * Propagate equality between two theory variables v1 and v2
3750  * - v1 = theory var of c1
3751  * - v2 = theory var of c2
3752  * - id = edge index that caused c1 and c2 to be merged
3753  *
3754  * This is called when c1 and c2 are merged:
3755  * - c1 remains root (and v1 remains visible in the egraph)
3756  * - c2 is no longer root after the merge (so v2 is no longer
3757  *   visible in the egraph).
3758  */
propagate_thvar_equality(egraph_t * egraph,class_t c1,thvar_t v1,class_t c2,thvar_t v2,int32_t id)3759 static void propagate_thvar_equality(egraph_t *egraph, class_t c1, thvar_t v1, class_t c2, thvar_t v2, int32_t id) {
3760   etype_t i;
3761 
3762   assert(v1 != null_thvar && v2 != null_thvar &&
3763          v1 == egraph_class_thvar(egraph, c1) &&
3764          v2 == egraph_class_thvar(egraph, c2));
3765 
3766   i = egraph->classes.etype[c1];
3767   switch (i) {
3768   case ETYPE_INT:
3769   case ETYPE_REAL:
3770   case ETYPE_BV:
3771   case ETYPE_FUNCTION:
3772     propagate_satellite_equality(egraph, i, v1, v2, id);
3773     break;
3774 
3775   case ETYPE_BOOL:
3776     propagate_boolean_equality(egraph, v1, v2, id);
3777     break;
3778 
3779   case ETYPE_TUPLE:
3780     propagate_tuple_equality(egraph, v1, v2);
3781     break;
3782 
3783   default:
3784     assert(false);
3785   }
3786 }
3787 
3788 
3789 /*
3790  * Remove equality between two theory variables v1 and v2
3791  * - this is used only for boolean variables
3792  * - satellite solvers remove equalities or disequalities by backtracking
3793  * - for tuple equalities, there's nothing to undo
3794  */
undo_thvar_equality(egraph_t * egraph,class_t c1,thvar_t v1,class_t c2,thvar_t v2)3795 static void undo_thvar_equality(egraph_t *egraph, class_t c1, thvar_t v1, class_t c2, thvar_t v2) {
3796   smt_core_t *core;
3797 
3798   assert(v1 != null_thvar && v2 != null_thvar &&
3799          v1 == egraph_class_thvar(egraph, c1) &&
3800          v2 == egraph_class_thvar(egraph, c2));
3801 
3802   if (egraph->classes.etype[c1] == ETYPE_BOOL) {
3803     core = egraph->core;
3804     assert(core != NULL && bvar_has_atom(core, v1) && bvar_has_atom(core, v2));
3805     split_atom_lists(get_bvar_atom(core, v1), get_bvar_atom(core, v2));
3806   }
3807 }
3808 
3809 
3810 /*
3811  * Hack: to ensure that undo_thvar_equality works when a conflict is detected
3812  * by check_atom_propagation, we merge the lists of atoms for Boolean variables v1 and v2.
3813  */
fixup_atom_lists(egraph_t * egraph,bvar_t v1,bvar_t v2)3814 static void fixup_atom_lists(egraph_t *egraph, bvar_t v1, bvar_t v2) {
3815   atom_t *atm1, *atm2;
3816   smt_core_t *core;
3817 
3818   core = egraph->core;
3819 
3820   assert(core != NULL && bvar_has_atom(core, v1) && bvar_has_atom(core, v2));
3821 
3822   atm1 = get_bvar_atom(core, v1);
3823   atm2 = get_bvar_atom(core, v2);
3824 
3825   merge_atom_lists(atm1, atm2);
3826 }
3827 
3828 
3829 
3830 /*********************
3831  *  ATOM ASSIGNMENT  *
3832  ********************/
3833 
3834 /*
3835  * Check for propagations when atom t --> (eq t1 t2) becomes true or false
3836  */
check_eq_atom(egraph_t * egraph,occ_t t,composite_t * atom)3837 static void check_eq_atom(egraph_t *egraph, occ_t t, composite_t *atom) {
3838   occ_t t1, t2;
3839   class_t c1, c2;
3840   thvar_t v1, v2;
3841   int32_t k;
3842   etype_t i;
3843 
3844   t &= ~0x1; // make sure t = pos_occ(atom->id);
3845   assert(t == pos_occ(atom->id) && atom->tag == mk_eq_tag());
3846 
3847   if (egraph_occ_is_true(egraph, t)) {
3848     t1 = atom->child[0];
3849     t2 = atom->child[1];
3850     if (! egraph_equal_occ(egraph, t1, t2)) {
3851       // (eq t1 t2) == true implies (t1 == t2)
3852       k = egraph_stack_push_eq(&egraph->stack, t1, t2);
3853       egraph->stack.etag[k] = EXPL_EQ;
3854       egraph->stack.edata[k].t[0] = t;
3855       egraph->stack.edata[k].t[1] = true_occ;
3856 #if TRACE
3857       printf("---> EGRAPH: equality ");
3858       print_occurrence(stdout, t1);
3859       printf(" == ");
3860       print_occurrence(stdout, t2);
3861       printf(" implied by ");
3862       print_composite(stdout, atom);
3863       printf(" == true\n");
3864 #endif
3865     }
3866 
3867   } else {
3868 
3869     assert(egraph_occ_is_false(egraph, t));
3870 
3871     t1 = atom->child[0];
3872     t2 = atom->child[1];
3873     i = egraph_type(egraph, t1);
3874 
3875     if (i < NUM_SATELLITES ) {
3876       /*
3877        * Propagate the disequality to a satellite solver, if needed.
3878        */
3879       c1 = egraph_class(egraph, t1);
3880       v1 = egraph->classes.thvar[c1];
3881       c2 = egraph_class(egraph, t2);
3882       v2 = egraph->classes.thvar[c2];
3883       if (v1 != null_thvar && v2 != null_thvar) {
3884         propagate_satellite_disequality(egraph, i, v1, v2, atom);
3885       }
3886 
3887     } else if (i == ETYPE_BOOL) {
3888       assert(egraph_type(egraph, t2) == ETYPE_BOOL);
3889       /*
3890        * Propagation rule: (eq t1 t2) == false implies (t1 == not t2)
3891        */
3892       if (! egraph_opposite_occ(egraph, t1, t2)) {
3893         k = egraph_stack_push_eq(&egraph->stack, t1, opposite_occ(t2));
3894         egraph->stack.etag[k] = EXPL_EQ;
3895         egraph->stack.edata[k].t[0] = t;
3896         egraph->stack.edata[k].t[1] = false_occ;
3897 #if TRACE
3898         printf("---> EGRAPH: equality ");
3899         print_occurrence(stdout, t1);
3900         printf(" == ");
3901         print_occurrence(stdout, opposite_occ(t2));
3902         printf(" implied by ");
3903         print_composite(stdout, atom);
3904         printf(" == false\n");
3905 #endif
3906       }
3907     }
3908   }
3909 }
3910 
3911 
3912 /*
3913  * Check whether the assertion (distinct t_1 ... t_n) can
3914  * be propagated to a satellite theory.
3915  * - atom = (distinct t_1 ... t_n)
3916  * - tau = the type of t_1
3917  */
check_satellite_distinct(egraph_t * egraph,etype_t tau,composite_t * atom)3918 static void check_satellite_distinct(egraph_t *egraph, etype_t tau, composite_t *atom) {
3919   ivector_t *v;
3920   uint32_t i, n;
3921   class_t c;
3922   thvar_t x;
3923 
3924   assert(tau < NUM_SATELLITES && composite_kind(atom) == COMPOSITE_DISTINCT);
3925 
3926   v = &egraph->aux_buffer;
3927   ivector_reset(v);
3928 
3929   // collect the theory variables in classes of t_1 ... t_n
3930   n = composite_arity(atom);
3931   for (i=0; i<n; i++) {
3932     c = egraph_class(egraph, atom->child[i]);
3933     x = egraph->classes.thvar[c];
3934     if (x != null_thvar) {
3935       ivector_push(v, x);
3936     }
3937   }
3938 
3939   if (v->size > 2) {
3940     propagate_satellite_distinct(egraph, tau, v->size, v->data, atom);
3941   } else if (v->size == 2) {
3942     propagate_satellite_disequality(egraph, tau, v->data[0], v->data[1], atom);
3943   }
3944 
3945 }
3946 
3947 
3948 /*
3949  * Assert (distinct t_1 ... t_n):
3950  * - assumes that this does not cause a conflict in the egraph. All children
3951  *   t_1 ... t_n must be in different classes.
3952  */
assert_distinct(egraph_t * egraph,composite_t * atom)3953 static void assert_distinct(egraph_t *egraph, composite_t *atom) {
3954   uint32_t k, i, n, j, m;
3955   uint32_t msk;
3956   class_t c, c1, c2;
3957   use_vector_t *v;
3958   composite_t *p;
3959   occ_t t1, t2;
3960   uint32_t *dmask;
3961   etype_t tau;
3962 
3963   assert(egraph->dtable.npreds < NDISTINCTS);
3964 
3965   // save data for backtracking
3966   undo_stack_push_distinct(&egraph->undo);
3967 
3968   // assign an index to atom in dtable
3969   k = egraph->dtable.npreds;
3970   egraph->dtable.distinct[k] = atom;
3971   egraph->dtable.npreds ++;
3972 
3973   dmask = egraph->classes.dmask;
3974 
3975   // update dmasks
3976   msk = ((uint32_t) 1) << k;
3977   n = composite_arity(atom);
3978   for (i=0; i<n; i++) {
3979     c = egraph_class(egraph, atom->child[i]);
3980     assert((dmask[c] & msk) == 0);
3981     dmask[c] |= msk;
3982   }
3983 
3984 #if TRACE
3985   printf("---> EGRAPH: asserting ");
3986   print_composite(stdout, atom);
3987   printf("\n");
3988 #endif
3989 
3990   // scan equality terms to check whether this makes them false
3991   for (i=0; i<n; i++) {
3992     c = egraph_class(egraph, atom->child[i]);
3993     v = egraph->classes.parents + c;
3994     m = v->last;
3995     for (j=0; j<m; j++) {
3996       p = v->data[j];
3997       if (valid_entry(p) && p->tag == mk_eq_tag()) {
3998         // p in v implies that p is in the congruence table,
3999         // so it was not false (or true) on entry to this function
4000         t1 = p->child[0];
4001         t2 = p->child[1];
4002         c1 = egraph_class(egraph, t1);
4003         c2 = egraph_class(egraph, t2);
4004         assert(c1 == c || c2 == c);
4005 
4006         if ((dmask[c1] & dmask[c2]) != 0) {
4007           assert((dmask[c1] & dmask[c2]) == msk);
4008           // p = (eq t1 t2) is false
4009           add_diseq_implies_eq(egraph, p, false_occ, t1, t2, msk);
4010           congruence_table_remove(&egraph->ctable, p);
4011           detach_composite(p, egraph->terms.label, egraph->classes.parents);
4012           assert(empty_entry(v->data[j]));
4013           // save p  to restore it on backtracking
4014           undo_stack_push_composite(&egraph->undo, p);
4015         }
4016 
4017       }
4018     }
4019   }
4020 
4021   /*
4022    * Propagate to a satellite solver if needed
4023    */
4024   tau = egraph_type(egraph, atom->child[0]);
4025   if (tau < NUM_SATELLITES) {
4026     check_satellite_distinct(egraph, tau, atom);
4027   }
4028 
4029 }
4030 
4031 
4032 /*
4033  * Process atom (distinct t_1 ... t_n) after it's asserted true or false.
4034  * - return false if there's a conflict
4035  */
check_distinct_atom(egraph_t * egraph,occ_t t,composite_t * atom)4036 static bool check_distinct_atom(egraph_t *egraph, occ_t t, composite_t *atom) {
4037   t &= ~0x1;
4038   assert(t == pos_occ(atom->id) && composite_kind(atom) == COMPOSITE_DISTINCT);
4039 
4040   if (egraph_occ_is_true(egraph, t)) {
4041     // It's redundant to check for a conflict if atom is
4042     // in the congruence table, but we don't know for sure.
4043     if (egraph_inconsistent_distinct(egraph, atom, &egraph->expl_vector)) {
4044       return false;
4045     } else {
4046       assert_distinct(egraph, atom);
4047     }
4048 
4049   } else {
4050 
4051     assert(egraph_occ_is_false(egraph, t));
4052 
4053     // important: egraph_inconsistent_not_distinct must be called
4054     // after egraph_check_distinct_false.
4055     if (egraph_check_distinct_false(egraph, atom)) {
4056       return true;
4057     }
4058 
4059     if (egraph_inconsistent_not_distinct(egraph, atom, &egraph->expl_vector)) {
4060       return false;
4061     }
4062 
4063     // expand (not (distinct ...))
4064     create_distinct_lemma(egraph, atom);
4065   }
4066 
4067   return true;
4068 }
4069 
4070 
4071 /*
4072  * Function called when t is assigned to true or false
4073  * Check whether t is an atom and if so assert the atom.
4074  * - return false if a conflict is detected
4075  */
check_atom_propagation(egraph_t * egraph,occ_t t)4076 static bool check_atom_propagation(egraph_t *egraph, occ_t t) {
4077   composite_t *atom;
4078 
4079   assert(egraph_class(egraph, t) == bool_constant_class);
4080 
4081   atom = egraph_term_body(egraph, term_of_occ(t));
4082   if (composite_body(atom)) {
4083     assert(atom != NULL);
4084     switch (composite_kind(atom)) {
4085     case COMPOSITE_EQ:
4086       check_eq_atom(egraph, t, atom);
4087       break;
4088 
4089     case COMPOSITE_DISTINCT:
4090       return check_distinct_atom(egraph, t, atom);
4091 
4092     default:
4093       // not an atom
4094       break;
4095     }
4096   }
4097 
4098   return true;
4099 }
4100 
4101 
4102 
4103 
4104 /***********************
4105  *  MERGE TWO CLASSES  *
4106  **********************/
4107 
4108 /*
4109  * Invert the edges on the branch from x to its root
4110  */
invert_branch(egraph_t * egraph,occ_t x)4111 static void invert_branch(egraph_t *egraph, occ_t x) {
4112   eterm_t t;
4113   int32_t i, j;
4114   equeue_elem_t *eq;
4115   int32_t *edge;
4116 
4117   eq = egraph->stack.eq;
4118   edge = egraph->terms.edge;
4119 
4120   t = term_of_occ(x);
4121   i = null_edge;
4122   for (;;) {
4123     j = edge[t];
4124     edge[t] = i;
4125     if (j < 0) break; // j == null_edge
4126     t = edge_next(eq + j, t);
4127     i = j;
4128   }
4129 }
4130 
4131 /*
4132  * Scan use vector u. Store all equality terms into v
4133  */
collect_eqterms(use_vector_t * u,pvector_t * v)4134 static void collect_eqterms(use_vector_t *u, pvector_t *v) {
4135   uint32_t i, n;
4136   composite_t *p;
4137 
4138   pvector_reset(v);
4139   n = u->last;
4140   for (i=0; i<n; i++) {
4141     p = u->data[i];
4142     if (valid_entry(p) && p->tag == mk_eq_tag()) {
4143       pvector_push(v, p);
4144     }
4145   }
4146 }
4147 
4148 /*
4149  * Check all composites in v: they are all equalities
4150  * check whether they have become false (after change in dmask).
4151  */
check_false_eq(egraph_t * egraph,pvector_t * v)4152 static void check_false_eq(egraph_t *egraph, pvector_t *v) {
4153   uint32_t i;
4154   composite_t *p;
4155   occ_t t1, t2;
4156   class_t c1, c2;
4157   uint32_t *dmask, msk;
4158 
4159   dmask = egraph->classes.dmask;
4160 
4161   for (i=0; i<v->size; i++) {
4162     p = v->data[i];
4163     assert(p->tag == mk_eq_tag());
4164     t1 = p->child[0];
4165     t2 = p->child[1];
4166     c1 = egraph_class(egraph, t1);
4167     c2 = egraph_class(egraph, t2);
4168     msk = dmask[c1] & dmask[c2];
4169     if (msk != 0) {
4170       // t1 != t2 implies (eq t1 t2) == false
4171       add_diseq_implies_eq(egraph, p, false_occ, t1, t2, msk);
4172       congruence_table_remove(&egraph->ctable, p);
4173       detach_composite(p, egraph->terms.label, egraph->classes.parents);
4174       // save p so it can be restored on backtracking
4175       undo_stack_push_composite(&egraph->undo, p);
4176     }
4177   }
4178 }
4179 
4180 /*
4181  * Check whether equality with index i is from a theory solver
4182  */
eq_is_from_satellite(egraph_t * egraph,int32_t i)4183 static bool eq_is_from_satellite(egraph_t *egraph, int32_t i) {
4184   expl_tag_t tag;
4185 
4186   assert(0 <= i && i < egraph->stack.top);
4187   tag = egraph->stack.etag[i];
4188   return tag == EXPL_ARITH_PROPAGATION || tag == EXPL_BV_PROPAGATION;
4189 }
4190 
4191 /*
4192  * Process equality (t1 == t2): i = corresponding edge id
4193  * - egraph->stack.eq[i] is (t1 == t2)
4194  * - egraph->stack.etag[i] + egraph->stack.edata[i] == antecedent/explanation
4195  *
4196  * - returned value: true means no inconsistency detected
4197  * - false means that a conflict was detected. The conflict literals are stored
4198  *   in egraph->expl_vector.
4199  */
process_equality(egraph_t * egraph,occ_t t1,occ_t t2,int32_t i)4200 static bool process_equality(egraph_t *egraph, occ_t t1, occ_t t2, int32_t i) {
4201   class_t c1, c2;
4202   int32_t aux;
4203   use_vector_t *v;
4204   uint32_t j, n, dmask;
4205   composite_t *p;
4206   elabel_t l;
4207   occ_t t;
4208   thvar_t v1, v2;
4209 
4210 #if TRACE
4211   printf("\n---> EGRAPH: processing equality ");
4212   print_occurrence(stdout, t1);
4213   printf(" == ");
4214   print_occurrence(stdout, t2);
4215   printf("\n");
4216   if (egraph_term_is_composite(egraph, term_of_occ(t1))) {
4217     printf("---> ");
4218     print_eterm_def(stdout, egraph, term_of_occ(t1));
4219   }
4220   if (egraph_term_is_composite(egraph, term_of_occ(t2))) {
4221     printf("---> ");
4222     print_eterm_def(stdout, egraph, term_of_occ(t2));
4223   }
4224 #endif
4225 
4226   // check whether (t1 == t2) is redundant
4227   if (egraph_equal_occ(egraph, t1, t2)) {
4228 #if TRACE
4229     printf("---> redundant\n");
4230     fflush(stdout);
4231 #endif
4232     return true;
4233   }
4234 
4235   // check whether it's inconsistent and if so construct the explanation
4236   if (egraph_inconsistent_edge(egraph, t1, t2, i, &egraph->expl_vector)) {
4237 #if TRACE
4238     printf("---> conflict\n");
4239     fflush(stdout);
4240 #endif
4241 
4242     if (egraph->stack.etag[i] == EXPL_BASIC_CONGRUENCE) {
4243       // store t1 t2 for local Ackermann generation
4244       egraph->ack_left = t1;
4245       egraph->ack_right = t2;
4246     }
4247 
4248     return false;
4249   }
4250 
4251 #if TRACE
4252   printf("---> merging ");
4253   print_label(stdout, egraph_label(egraph, t1));
4254   printf(" and ");
4255   print_label(stdout, egraph_label(egraph, t2));
4256   printf("\n");
4257   fflush(stdout);
4258 #endif
4259 
4260   /*
4261    * Merge class of t2 into class of t1
4262    */
4263   c1 = egraph_class(egraph, t1);
4264   c2 = egraph_class(egraph, t2);
4265 
4266   assert(c1 != c2 && (egraph->classes.dmask[c1] & egraph->classes.dmask[c2]) == 0);
4267 
4268   // swap if necessary: we want c1 := union(c1, c2)
4269   // and we want to keep bool_constant_class as the root class
4270   if (c2 == bool_constant_class ||
4271       (c1 != bool_constant_class && egraph_class_nparents(egraph, c2) > egraph_class_nparents(egraph, c1))) {
4272     aux = t1; t1 = t2; t2 = aux;
4273     aux = c1; c1 = c2; c2 = aux;
4274   }
4275 
4276   // save t2 and its current label for backtracking
4277   undo_stack_push_merge(&egraph->undo, t2, egraph_label(egraph, t2));
4278 
4279   // update explanation tree: make t2 root of its tree
4280   invert_branch(egraph, t2);
4281   assert(egraph->terms.edge[term_of_occ(t2)] == null_edge);
4282   egraph->terms.edge[term_of_occ(t2)] = i; // new edge: t2 ---> t1
4283 
4284   /*
4285    * remove c2's parents from the congruence table
4286    * since their signature will change.
4287    */
4288   v = egraph->classes.parents + c2;
4289   n = v->last;
4290   for (j=0; j<n; j++) {
4291     p = v->data[j];
4292     if (valid_entry(p)) {
4293       // p is valid, i.e., it's in the congruence table
4294       congruence_table_remove(&egraph->ctable, p);
4295       // remove p from the parent vectors, except v
4296       separate_composite(p, egraph->terms.label, egraph->classes.parents, c2);
4297       assert(v->data[j] == p);
4298     }
4299   }
4300 
4301   /*
4302    * Assign new label to all terms in t2's class:
4303    * new label == current label of t1
4304    */
4305   l = egraph_label(egraph, t1);
4306   t = t2;
4307   do {
4308     egraph_set_label(egraph, t, l);
4309     t = egraph_next(egraph, t);
4310     assert(term_of_occ(t) != term_of_occ(t2) || t == t2);
4311   } while (t != t2);
4312 
4313   // update dmask of c1
4314   dmask = egraph->classes.dmask[c1];
4315   egraph->classes.dmask[c1] |= egraph->classes.dmask[c2];
4316 
4317   //  merge lists of terms: swap next[t1] and next[t2]
4318   t = egraph_next(egraph, t2);
4319   egraph_set_next(egraph, t2, egraph_next(egraph, t1));
4320   egraph_set_next(egraph, t1, t);
4321 
4322   /*
4323    * For propagation: if dmask[c1] has changed, some equality
4324    * terms in parents[c1] may have become false. Collect them
4325    * into egraph->cmp_vector.
4326    */
4327   if (egraph->classes.dmask[c1] != dmask) {
4328     collect_eqterms(egraph->classes.parents + c1, &egraph->cmp_vector);
4329   }
4330 
4331   /*
4332    * Reprocess all composites in v == all parents of c2
4333    *
4334    * For backtracking, we keep all these composites in v
4335    * - if p remains a congruence root, it's kept as is in v
4336    * - if p is no longer a congruence root, it's kept as a marked
4337    *   pointer in v.
4338    */
4339   for (j=0; j<n; j++) {
4340     p = v->data[j];
4341     if (valid_entry(p)) {
4342       if (composite_simplifies(egraph, p)) {
4343         // p is no longer in the congruence table
4344         // put a mark for backtracking
4345         mark_use_vector_entry(v, j);
4346       } else {
4347         // put p back into the use vectors
4348         // this adds p into c1's parent vector
4349         attach_composite(p, egraph->terms.label, egraph->classes.parents);
4350       }
4351     }
4352   }
4353 
4354 
4355   /*
4356    * Propagation 1: visit all equality terms in cmp_vector:
4357    * check whether they have become false.
4358    */
4359   if (egraph->classes.dmask[c1] != dmask) {
4360     check_false_eq(egraph, &egraph->cmp_vector);
4361   }
4362 
4363   /*
4364    * Propagation 2: if c1 == bool_constant_class, some atoms may
4365    * have become true or false.
4366    */
4367   if (c1 == bool_constant_class) {
4368     // atoms to visit = terms that were in t2's class.
4369     // now they are in the list t1->next ... --> t2
4370     t = t1;
4371     do {
4372       t = egraph_next(egraph, t);
4373       if (! check_atom_propagation(egraph, t)) {
4374         // conflict
4375 
4376         /*
4377          * HACK/BUG FIX: this fixes a bug reported by Dorus Peelen.
4378          *
4379          * Before returning false, we must merge the atoms of v1 and v2
4380          * otherwise the backtracking will fail; it will call undo_thvar_equality,
4381          * and that function requires the lists of atoms of v1 and v2 to be merged.
4382          */
4383         v1 = egraph->classes.thvar[c1];
4384         v2 = egraph->classes.thvar[c2];
4385         assert(v1 != null_thvar && v2 != null_thvar);
4386         fixup_atom_lists(egraph, v1, v2);
4387         return false;
4388       }
4389     } while (t != t2);
4390   }
4391 
4392   /*
4393    * Deal with theory variables of c1 and c2:
4394    * - if c2 has a theory var v2 but not c1, set v2 as theory var of c1
4395    * - if both have a theory variable, propagate equality (v1 == v2) to theory solvers
4396    * - check the explanation for i before propagating to the theory solver
4397    *   if the equality i was propagated from Simplex or BV solver, there's no point
4398    *   sending v1 == v2 to this solver (and doing so pauses a circularity problem).
4399    *
4400    * NOTE: this is also how we propagate tuple/boolean equalities
4401    *
4402    * TODO:
4403    * - extend this to deal with equalities between lambda terms
4404    *     (lambda t x) == (lambda t y) ==> (x == y) since t does not occur in x or y
4405    *   this requires removing the satellite solver for array/function theory
4406    *   and move support for these theories here (cf. update_graph)
4407    */
4408   if (!eq_is_from_satellite(egraph, i)) {
4409     v2 = egraph->classes.thvar[c2];
4410     if (v2 != null_thvar) {
4411       v1 = egraph->classes.thvar[c1];
4412       if (v1 != null_thvar) {
4413         propagate_thvar_equality(egraph, c1, v1, c2, v2, i);
4414       } else {
4415         egraph->classes.thvar[c1] = v2;
4416       }
4417     }
4418   }
4419 
4420 #if TRACE_FCHECK
4421   printf("\nDONE PROCESSING EQUALITY\n\n");
4422   print_egraph_terms(stdout, egraph);
4423   printf("\n");
4424   print_egraph_root_classes_details(stdout, egraph);
4425   fflush(stdout);
4426 #endif
4427 
4428   return true;
4429 }
4430 
4431 
4432 
4433 
4434 /***************************
4435  *  INTERNALIZATION START  *
4436  **************************/
4437 
4438 /*
4439  * Set the presearch flag. Propagate the call to the satellite solvers
4440  */
egraph_start_internalization(egraph_t * egraph)4441 void egraph_start_internalization(egraph_t *egraph) {
4442   uint32_t i;
4443 
4444   egraph->presearch = true;
4445 
4446   for (i=0; i<NUM_SATELLITES; i++) {
4447     if (egraph->ctrl[i] != NULL) {
4448       egraph->ctrl[i]->start_internalization(egraph->th[i]);
4449     }
4450   }
4451 }
4452 
4453 
4454 
4455 /******************
4456  *  START SEARCH  *
4457  *****************/
4458 
egraph_start_search(egraph_t * egraph)4459 void egraph_start_search(egraph_t *egraph) {
4460   uint32_t i;
4461 
4462 #if TRACE
4463   fprintf(stdout, "---> EGRAPH START_SEARCH [dlevel = %"PRIu32", decisions = %"PRIu64"]\n",
4464           egraph->decision_level, egraph->core->stats.decisions);
4465   fprintf(stdout, "\n=== EGRAPH TERMS ===\n");
4466   print_egraph_terms(stdout, egraph);
4467   fprintf(stdout, "\n");
4468 #endif
4469 
4470   assert(egraph->core != NULL && egraph->decision_level == egraph->base_level);
4471 
4472   egraph->stats.eq_props = 0;
4473   egraph->stats.th_props = 0;
4474   egraph->stats.th_conflicts = 0;
4475 
4476   egraph->stats.final_checks = 0;
4477   egraph->stats.interface_eqs = 0;
4478 
4479   for (i=0; i<NUM_SATELLITES; i++) {
4480     if (egraph->ctrl[i] != NULL) {
4481       egraph->ctrl[i]->start_search(egraph->th[i]);
4482     }
4483   }
4484 
4485 #if TRACE
4486   printf("\n=== EGRAPH TERMS ===\n");
4487   print_egraph_terms(stdout, egraph);
4488   printf("\n");
4489 #endif
4490 
4491   egraph->presearch = false;
4492 }
4493 
4494 
4495 
4496 /*****************************
4497  *  INCREASE DECISION LEVEL  *
4498  ****************************/
4499 
egraph_open_decision_level(egraph_t * egraph)4500 static void egraph_open_decision_level(egraph_t *egraph) {
4501   uint32_t k;
4502 
4503   k = egraph->decision_level + 1;
4504   egraph->decision_level = k;
4505   if (egraph->stack.nlevels <= k) {
4506     increase_egraph_stack_levels(&egraph->stack);
4507   }
4508   egraph->stack.level_index[k] = egraph->stack.top;
4509 
4510   if (egraph->undo.nlevels <= k) {
4511     increase_undo_stack_levels(&egraph->undo);
4512   }
4513   egraph->undo.level_index[k] = egraph->undo.top;
4514 
4515   // open new scope in arena
4516   arena_push(&egraph->arena);
4517 
4518 #if TRACE
4519   printf("\n---> Egraph: increase decision level to %"PRIu32"\n", egraph->decision_level);
4520 #endif
4521 }
4522 
4523 
4524 /*
4525  * Increase the decision level
4526  * - the propagation queue should be empty
4527  */
egraph_increase_decision_level(egraph_t * egraph)4528 void egraph_increase_decision_level(egraph_t *egraph) {
4529   uint32_t i;
4530 
4531   assert(egraph->stack.prop_ptr == egraph->stack.top);
4532 
4533   egraph_open_decision_level(egraph);
4534 
4535   // forward to satellite solvers
4536   for (i=0; i<NUM_SATELLITES; i++) {
4537     if (egraph->ctrl[i] != NULL) {
4538       egraph->ctrl[i]->increase_decision_level(egraph->th[i]);
4539     }
4540   }
4541 }
4542 
4543 
4544 /**********
4545  *  PUSH  *
4546  *********/
4547 
egraph_push(egraph_t * egraph)4548 void egraph_push(egraph_t *egraph) {
4549   uint32_t i;
4550 
4551   assert(egraph->decision_level == egraph->base_level);
4552   assert(egraph->terms.nterms == egraph->classes.nclasses);
4553   assert(egraph->reanalyze_vector.size == 0);
4554 
4555   // save number of terms == number of classes, and propagation pointer
4556   egraph_trail_save(&egraph->trail_stack, egraph->terms.nterms, egraph->stack.prop_ptr);
4557 
4558   // mark cache content
4559   cache_push(&egraph->cache);
4560 
4561   // forward to the satellite solvers
4562   for (i=0; i<NUM_SATELLITES; i++) {
4563     if (egraph->ctrl[i] != NULL) {
4564       egraph->ctrl[i]->push(egraph->th[i]);
4565     }
4566   }
4567 
4568   // increase base level and decision level
4569   egraph->base_level ++;
4570   egraph_open_decision_level(egraph);
4571 
4572 #if 0
4573   printf("\n*** EGRAPH PUSH EXIT ****\n");
4574   print_egraph_root_classes_details(stdout, egraph);
4575   print_egraph_congruence_roots(stdout, egraph);
4576 #endif
4577 
4578 }
4579 
4580 
4581 
4582 /***********
4583  *  RESET  *
4584  **********/
4585 
4586 /*
4587  * - remove all terms, classes, and atoms
4588  * - reset all stacks and tables
4589  * - set base_level and decision_level to 0
4590  */
egraph_reset(egraph_t * egraph)4591 void egraph_reset(egraph_t *egraph) {
4592   uint32_t i;
4593 
4594   egraph->base_level = 0;
4595   egraph->decision_level = 0;
4596   egraph->presearch = false;
4597   egraph->ndistincts = 0;
4598   egraph->natoms = 0;
4599   egraph->is_high_order = false;
4600 
4601   reset_egraph_stats(&egraph->stats);
4602   egraph->ack_left = null_occurrence;
4603   egraph->ack_right = null_occurrence;
4604 
4605   reset_class_table(&egraph->classes);
4606   reset_eterm_table(&egraph->terms);
4607   reset_egraph_stack(&egraph->stack);
4608   reset_undo_stack(&egraph->undo);
4609   reset_distinct_table(&egraph->dtable);
4610   reset_congruence_table(&egraph->ctable);
4611   reset_ltag_table(&egraph->tag_table);
4612   reset_egraph_trail(&egraph->trail_stack);
4613 
4614   egraph_free_const_htbl(egraph);
4615   reset_int_htbl(&egraph->htbl);
4616   reset_objstore(&egraph->atom_store);  // delete all atoms
4617   reset_cache(&egraph->cache);
4618   arena_reset(&egraph->arena);
4619   reset_istack(&egraph->istack);
4620 
4621   ivector_reset(&egraph->interface_eqs);
4622   egraph->reconcile_top = 0;
4623   egraph->reconcile_neqs = 0;
4624   egraph->reconcile_mode = false;
4625 
4626   if (egraph->app_partition != NULL) {
4627     delete_ptr_partition(egraph->app_partition);
4628     safe_free(egraph->app_partition);
4629     egraph->app_partition = NULL;
4630   }
4631 
4632   egraph_init_constant(egraph);
4633 
4634   // model-building objects
4635   reset_egraph_model(&egraph->mdl);
4636 
4637   // forward reset to the satellite solvers
4638   for (i=0; i<NUM_SATELLITES; i++) {
4639     if (egraph->ctrl[i] != NULL) {
4640       egraph->ctrl[i]->reset(egraph->th[i]);
4641     }
4642   }
4643 }
4644 
4645 
4646 
4647 
4648 
4649 /*******************
4650  *  BACKTRACKING   *
4651  ******************/
4652 
4653 /*
4654  * Undo operation: remove the last (distinct ...)
4655  */
undo_distinct(egraph_t * egraph)4656 static void undo_distinct(egraph_t *egraph) {
4657   uint32_t k, msk, i, n;
4658   uint32_t *dmask;
4659   composite_t *d;
4660   class_t c;
4661 
4662   assert(egraph->dtable.npreds > 1);
4663 
4664   k = egraph->dtable.npreds - 1;
4665   d = egraph->dtable.distinct[k];
4666   egraph->dtable.npreds = k;
4667 
4668   // clear bit k in dmasks
4669   dmask = egraph->classes.dmask;
4670   msk = ~(((uint32_t) 1) << k);
4671 
4672   assert(d != NULL && composite_kind(d) == COMPOSITE_DISTINCT);
4673   n = composite_arity(d);
4674   for (i=0; i<n; i++) {
4675     c = egraph_class(egraph, d->child[i]);
4676     assert((dmask[c] & ~msk) == ~msk);
4677     dmask[c] &= msk;
4678   }
4679 }
4680 
4681 
4682 /*
4683  * Put composite cmp back into its parents vector
4684  * and into the congruence table.
4685  */
restore_composite(egraph_t * egraph,composite_t * cmp)4686 static void restore_composite(egraph_t *egraph, composite_t *cmp) {
4687 #ifndef NDEBUG
4688   // cmp->hash should be valid
4689   signature_composite(cmp, egraph->terms.label, &egraph->sgn);
4690   assert(cmp->hash == hash_signature(&egraph->sgn));
4691 #endif
4692   congruence_table_add(&egraph->ctable, cmp);
4693   attach_composite(cmp, egraph->terms.label, egraph->classes.parents);
4694 }
4695 
4696 
4697 /*
4698  * Undo merge: t2 = saved occurrence, l2 = saved label
4699  * - let i = edge[t2] then egraph->stack.eq[i] is either <t1, t2> or <t2, t1>
4700  * - undo merge is the converse of process_equality(t1, t2, i):
4701  */
undo_merge(egraph_t * egraph,occ_t t2,elabel_t l2)4702 static void undo_merge(egraph_t *egraph, occ_t t2, elabel_t l2) {
4703   class_t c1, c2;
4704   occ_t t1, t;
4705   int32_t i, n;
4706   use_vector_t *v;
4707   composite_t *p;
4708   elabel_t *label;
4709 
4710   c1 = egraph_class(egraph, t2);
4711   c2 = class_of(l2);
4712 
4713   i = egraph->terms.edge[term_of_occ(t2)];
4714   assert(0 <= i && i < egraph->stack.top);
4715 
4716   t1 = edge_next_occ(egraph->stack.eq + i, t2);
4717   assert(egraph_class(egraph, t1) == c1);
4718 
4719   /*
4720    * parents[c2] stores composites that need to be reinserted
4721    * in ctable after relabeling.
4722    * - marked elements in parents[c2] --> not currently in ctable
4723    * - valid elements in parents[c2] --> still in ctable
4724    * First loop: remove all composites in parents[c2] from ctable,
4725    * remove mark from the marked elements.
4726    */
4727   label = egraph->terms.label;
4728   v = egraph->classes.parents + c2;
4729   n = v->last;
4730   for (i=0; i<n; i++) {
4731     p = v->data[i];
4732     if (valid_entry(p)) {
4733       congruence_table_remove(&egraph->ctable, p);
4734       detach_composite(p, label, egraph->classes.parents);
4735     } else if (marked_entry(p)) {
4736       unmark_use_vector_entry(v, i);
4737     }
4738   }
4739 
4740   /*
4741    * class c1 is a circular list of the form
4742    * t1 --> x .... --> t2 --> y ... --> t1
4743    * we split it in into two circular sublists:
4744    * t2 --> x ... --> t2  and t1 --> y ... -> t1
4745    */
4746   t = egraph_next(egraph, t2);
4747   egraph_set_next(egraph, t2, egraph_next(egraph, t1));
4748   egraph_set_next(egraph, t1, t);
4749 
4750   // restore label l2 to t2 and all terms in its list
4751   t = t2;
4752   do {
4753     egraph_set_label(egraph, t, l2);
4754     t = egraph_next(egraph, t);
4755     assert(term_of_occ(t) != term_of_occ(t2) || t == t2);
4756   } while (t != t2);
4757 
4758   // restore dmask of c1
4759   egraph->classes.dmask[c1] &= ~egraph->classes.dmask[c2];
4760 
4761   // remove edge from t2 --> t1 then restore branch t2 ---> c2.root
4762   egraph->terms.edge[term_of_occ(t2)] = null_edge;
4763   invert_branch(egraph, egraph->classes.root[c2]);
4764 
4765   /*
4766    * Put parents[c2] back into ctable
4767    */
4768   for (i=0; i<n; i++) {
4769     p = v->data[i];
4770     assert(valid_entry(p) || empty_entry(p));
4771     if (valid_entry(p)) {
4772       signature_composite(p, label, &egraph->sgn);
4773       p->hash = hash_signature(&egraph->sgn);
4774       // p should be a congruence root
4775       assert(congruence_table_find(&egraph->ctable, &egraph->sgn, label) == NULL_COMPOSITE);
4776 
4777       congruence_table_add(&egraph->ctable, p);
4778       clear_use_vector_entry(v, i); // required for attach_composite
4779       attach_composite(p, label, egraph->classes.parents);
4780     }
4781   }
4782 
4783   /*
4784    * Restore theory variables:
4785    * if thvar[c1] == thvar[c2] != null, then we restore thvar[c1] to null
4786    * if thvar[c1] != thvar[c2] and thvar[c2] != null, undo_thvar_equality
4787    * does any extra processing needed.
4788    *
4789    * Exception: if c1 == bool_constant_class, it may happen that
4790    * thvar[c1] == thvar[2] == const_bvar: but we don't want to
4791    * set thvar[c1] to null_thvar.
4792    */
4793   if (egraph->classes.thvar[c2] != null_thvar) {
4794     assert(egraph->classes.thvar[c1] != null_thvar);
4795     if (egraph->classes.thvar[c1] == egraph->classes.thvar[c2])  {
4796       if (c1 != bool_constant_class) {
4797         egraph->classes.thvar[c1] = null_thvar;
4798       }
4799     } else {
4800       undo_thvar_equality(egraph, c1, egraph->classes.thvar[c1], c2, egraph->classes.thvar[c2]);
4801     }
4802   }
4803 
4804 }
4805 
4806 
4807 /*
4808  * Remove a congruence root from the congruence table and use vectors.
4809  * - at the time this function is called, p should be in a singleton
4810  *   class c (the class created when p was activated).
4811  */
deactivate_congruence_root(egraph_t * egraph,composite_t * p)4812 static void deactivate_congruence_root(egraph_t *egraph, composite_t *p) {
4813 #ifndef NDEBUG
4814   class_t c;
4815   eterm_t t;
4816 #endif
4817   elabel_t *label;
4818 
4819   label = egraph->terms.label;
4820 
4821 #ifndef NDEBUG
4822   t = p->id;
4823   c = egraph_term_class(egraph, t);
4824 
4825   // check that p->hash is valid
4826   signature_composite(p, label, &egraph->sgn);
4827   assert(p->hash == hash_signature(&egraph->sgn));
4828 
4829   // check that p is in ctable
4830   assert(congruence_table_find(&egraph->ctable, &egraph->sgn, label) == p);
4831 
4832   // t should be root of c and c should contain t only
4833   assert(egraph->classes.root[c] == pos_occ(t));
4834   assert(egraph->terms.next[t] == pos_occ(t));
4835 #endif
4836 
4837   congruence_table_remove(&egraph->ctable, p);
4838   detach_composite(p, label, egraph->classes.parents);
4839 }
4840 
4841 
4842 /*
4843  * Generate the ackermann lemma for term occurrences t1 and t2
4844  */
egraph_gen_ackermann_lemma(egraph_t * egraph,occ_t t1,occ_t t2)4845 static void egraph_gen_ackermann_lemma(egraph_t *egraph, occ_t t1, occ_t t2) {
4846   composite_t *c1, *c2;
4847 
4848   c1 = egraph_term_body(egraph, term_of_occ(t1));
4849   c2 = egraph_term_body(egraph, term_of_occ(t2));
4850   create_ackermann_lemma(egraph, c1, c2);
4851 }
4852 
4853 
4854 /*
4855  * Backtrack to back_level
4856  * (we need to isolate this because it's used in pop);
4857  */
egraph_local_backtrack(egraph_t * egraph,uint32_t back_level)4858 static void egraph_local_backtrack(egraph_t *egraph, uint32_t back_level) {
4859   uint32_t i, k;
4860   unsigned char *utag;
4861   undo_t *udata;
4862   uint32_t n;
4863 
4864   assert(egraph->base_level <= back_level && back_level < egraph->decision_level);
4865 
4866 #if TRACE
4867   printf("---> EGRAPH:   Backtracking to level %"PRIu32"\n\n", back_level);
4868 #endif
4869 
4870 
4871   /*
4872    * Generate ackermann lemmas if enabled: this must be done first
4873    */
4874   if (egraph->ack_left != null_occurrence &&
4875       egraph_option_enabled(egraph, EGRAPH_DYNAMIC_ACKERMANN | EGRAPH_DYNAMIC_BOOLACKERMANN)) {
4876     assert(egraph->ack_right != null_occurrence);
4877     egraph_gen_ackermann_lemma(egraph, egraph->ack_left, egraph->ack_right);
4878     egraph->ack_left = null_occurrence;
4879     egraph->ack_right = null_occurrence;
4880   }
4881 
4882 
4883   // undo everything in undo_stack[k ... top-1]
4884   k = egraph->undo.level_index[back_level + 1];
4885   i = egraph->undo.top;
4886   utag = egraph->undo.tag;
4887   udata = egraph->undo.data;
4888   while (i > k) {
4889     i --;
4890     switch (utag[i]) {
4891     case UNDO_MERGE:
4892       undo_merge(egraph, udata[i].merge.saved_occ, udata[i].merge.saved_label);
4893       break;
4894 
4895     case UNDO_DISTINCT:
4896       undo_distinct(egraph);
4897       break;
4898 
4899     case UNDO_SIMPLIFY:
4900       restore_composite(egraph, udata[i].ptr);
4901       break;
4902 
4903     // store terms to reanalyze into reanalyze_vector
4904     case REANALYZE_CONGRUENCE_ROOT:
4905       deactivate_congruence_root(egraph, udata[i].ptr);
4906       pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
4907       break;
4908 
4909     case REANALYZE_COMPOSITE:
4910       pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
4911       break;
4912 
4913     default:
4914       assert(false);
4915     }
4916   }
4917   assert(i == k);
4918   egraph->undo.top = k;
4919 
4920   // Cleanup the propagation stack
4921   k = egraph->stack.level_index[back_level + 1];
4922   egraph->stack.top = k;
4923   egraph->stack.prop_ptr = k;
4924 
4925   // delete all temporary data in the arena
4926   n = egraph->decision_level;
4927   do {
4928     arena_pop(&egraph->arena);
4929     n --;
4930   } while (n > back_level);
4931 
4932   egraph->decision_level = back_level;
4933 }
4934 
4935 
4936 /*
4937  * Full backtrack: egraph + all satellite solvers
4938  */
egraph_backtrack(egraph_t * egraph,uint32_t back_level)4939 void egraph_backtrack(egraph_t *egraph, uint32_t back_level) {
4940   uint32_t i;
4941 
4942   egraph_local_backtrack(egraph, back_level);
4943   if (back_level == egraph->base_level && egraph->reanalyze_vector.size > 0) {
4944     egraph_reactivate_dynamic_terms(egraph);
4945   }
4946 
4947   // forward to the satellite solvers
4948   for (i=0; i<NUM_SATELLITES; i++) {
4949     if (egraph->ctrl[i] != NULL) {
4950       egraph->ctrl[i]->backtrack(egraph->th[i], back_level);
4951     }
4952   }
4953 }
4954 
4955 
4956 
4957 /*********
4958  *  POP  *
4959  ********/
4960 
4961 /*
4962  * Delete composite p
4963  * - remove it from the congruence table and parent vectors
4964  *   if it's a congruence root
4965  * - also remove the corresponding record from the htbl
4966  */
delete_composite(egraph_t * egraph,composite_t * p)4967 static void delete_composite(egraph_t *egraph, composite_t *p) {
4968   elabel_t *label;
4969   uint32_t h;
4970 
4971   label = egraph->terms.label;
4972 
4973   // compute p->hash
4974   signature_composite(p, label, &egraph->sgn);
4975   p->hash = hash_signature(&egraph->sgn);
4976 
4977   if (congruence_table_remove_if_present(&egraph->ctable, p)) {
4978     detach_composite(p, label, egraph->classes.parents);
4979   }
4980 
4981   // hash code used in hash-consing
4982   h = hash_composite(p);
4983   int_htbl_erase_record(&egraph->htbl, h, p->id);
4984 
4985   safe_free(p);
4986 }
4987 
4988 
4989 /*
4990  * Cleanup the term table
4991  * - remove terms of id n to nterms - 1
4992  */
restore_eterms(egraph_t * egraph,uint32_t n)4993 static void restore_eterms(egraph_t *egraph, uint32_t n) {
4994   composite_t *cmp;
4995   eterm_t t;
4996   thvar_t x;
4997   atom_t *atom;
4998 
4999   t = egraph->terms.nterms;
5000   assert(t >= n);
5001 
5002   while (t > n) {
5003     t --;
5004     cmp = egraph_term_body(egraph, t);
5005     if (composite_body(cmp)) {
5006       delete_composite(egraph, cmp);
5007     } else if (constant_body(cmp)) {
5008       egraph_delete_constant(egraph, t);
5009     }
5010 
5011     x = egraph_term_thvar(egraph, t);
5012     assert(x == egraph_term_base_thvar(egraph, t) ||
5013            (x == null_thvar && egraph_term_base_thvar(egraph, t) == const_bvar)); // special case: cf. assert_pred_axiom
5014 
5015     /*
5016      * another special case: in assert_distinct_axiom, we attach t
5017      * to the theory variable const_var (i.e., 0) and we don't want
5018      * to delete the corresponding atom here.
5019      */
5020     if (x != null_thvar && x != const_bvar && egraph_term_type(egraph, t) == ETYPE_BOOL) {
5021       // remove atom if there's one
5022       atom = get_egraph_atom_for_bvar(egraph, x);
5023       if (atom != NULL) {
5024         delete_egraph_atom(egraph, atom);
5025       }
5026     }
5027   }
5028 
5029   egraph->terms.nterms = n;
5030 }
5031 
5032 
5033 /*
5034  * Cleanup the class table: remove class of ids n to nclasses - 1
5035  */
restore_classes(egraph_t * egraph,uint32_t n)5036 static void restore_classes(egraph_t *egraph, uint32_t n) {
5037   class_t c;
5038 
5039   c = egraph->classes.nclasses;
5040   assert(c >= n);
5041 
5042   while (c > n) {
5043     c --;
5044     free_parents(&egraph->classes, c);
5045   }
5046   egraph->classes.nclasses = n;
5047 }
5048 
5049 
5050 #ifndef NDEBUG
5051 /*
5052  * For debugging: check that all composites in the reanalyze_vector
5053  * are terms to be deleted.
5054  */
reanalyze_to_delete(egraph_t * egraph)5055 static bool reanalyze_to_delete(egraph_t *egraph) {
5056   pvector_t *v;
5057   composite_t *p;
5058   uint32_t i, n, k;
5059 
5060   // k = index of the first term to delete. All terms with id < k must
5061   // be preserved.
5062   k = egraph_trail_top(&egraph->trail_stack)->nterms;
5063 
5064   v = &egraph->reanalyze_vector;
5065   n = v->size;
5066   for (i=0; i<n; i++) {
5067     p = v->data[i];
5068     if (p->id < k) {
5069       return false;
5070     }
5071   }
5072 
5073   return true;
5074 }
5075 #endif
5076 
5077 
5078 /*
5079  * Return to the previous base_level
5080  */
egraph_pop(egraph_t * egraph)5081 void egraph_pop(egraph_t *egraph) {
5082   egraph_trail_t *trail;
5083   uint32_t i;
5084 
5085 #if 0
5086   printf("*** EGRAPH POP ENTRY ****\n");
5087   print_egraph_root_classes_details(stdout, egraph);
5088   print_egraph_congruence_roots(stdout, egraph);
5089 #endif
5090 
5091   assert(egraph->base_level > 0 && egraph->base_level == egraph->decision_level);
5092   assert(egraph->reanalyze_vector.size == 0);
5093 
5094   // decrease base_level then backtrack
5095   egraph->ack_left = null_occurrence;
5096   egraph->ack_right = null_occurrence;
5097   egraph->base_level --;
5098   egraph_local_backtrack(egraph, egraph->base_level);
5099 
5100   // local_backtrack may have moved terms to the reanalyze_vector
5101   // these should all be dead term so we can empty the reanalyze_vector.
5102   assert(reanalyze_to_delete(egraph));
5103   pvector_reset(&egraph->reanalyze_vector);
5104 
5105   // clear the high-order flag
5106   egraph->is_high_order = false;
5107 
5108   // remove all terms and classes of id >= trail->nterms
5109   trail = egraph_trail_top(&egraph->trail_stack);
5110   restore_eterms(egraph, trail->nterms);
5111   restore_classes(egraph, trail->nterms);
5112 
5113   // restore the propagation pointer
5114   egraph->stack.prop_ptr = trail->prop_ptr;
5115 
5116   // cleanup the cache
5117   cache_pop(&egraph->cache);
5118 
5119   // remove top trail element
5120   egraph_trail_pop(&egraph->trail_stack);
5121 
5122   // forward pop to the satellite solvers
5123   for (i=0; i<NUM_SATELLITES; i++) {
5124     if (egraph->ctrl[i] != NULL) {
5125       egraph->ctrl[i]->pop(egraph->th[i]);
5126     }
5127   }
5128 
5129 #if 0
5130   printf("\n*** EGRAPH POP: EXIT ****\n");
5131   print_egraph_root_classes_details(stdout, egraph);
5132   print_egraph_congruence_roots(stdout, egraph);
5133 #endif
5134 
5135 }
5136 
5137 
5138 
5139 /*****************
5140  *  PROPAGATION  *
5141  ****************/
5142 
5143 /*
5144  * Propagation via equality propagation queue.
5145  * Return false if a conflict is detected, true otherwise.
5146  * If there's a conflict, it is stored (as a conjunction of literals) in egraph->expl_vector.
5147  */
egraph_internal_propagation(egraph_t * egraph)5148 static bool egraph_internal_propagation(egraph_t *egraph) {
5149   equeue_elem_t *e;
5150   uint32_t i;
5151 
5152   // reactivate any composite in the reanalyze_vector
5153   if (egraph->reanalyze_vector.size > 0) {
5154     egraph_reactivate_dynamic_terms(egraph);
5155   }
5156 
5157   // process the equality queue
5158   i = egraph->stack.prop_ptr;
5159   while (i < egraph->stack.top) {
5160     e = egraph->stack.eq + i;
5161     if (! process_equality(egraph, e->lhs, e->rhs, i)) {
5162 #if 0
5163       printf("---> EGRAPH CONFLICT on ");
5164       print_occurrence(stdout, e->lhs);
5165       printf(" == ");
5166       print_occurrence(stdout, e->rhs);
5167       printf("\n     explanation: ");
5168       print_egraph_conflict(stdout, egraph, &egraph->expl_vector);
5169       printf("\n");
5170       fflush(stdout);
5171 #endif
5172       egraph->stack.prop_ptr = i;
5173       return false;
5174     }
5175     i ++;
5176   }
5177   egraph->stack.prop_ptr = i;
5178 
5179   return true;
5180 }
5181 
5182 
5183 /*
5184  * Full propagation: in egraph and satellite solvers
5185  * Return false if there's a conflict, true otherwise.
5186  * If the conflict is in the egraph, report it to the core.
5187  */
egraph_propagate(egraph_t * egraph)5188 bool egraph_propagate(egraph_t *egraph) {
5189   uint32_t i, k;
5190   ivector_t *conflict;
5191 
5192 #if TRACE
5193   printf("---> EGRAPH PROPAGATE [dlevel = %"PRIu32", decisions = %"PRIu64"]\n",
5194          egraph->decision_level, egraph->core->stats.decisions);
5195 #endif
5196 
5197   do {
5198     if (! egraph_internal_propagation(egraph)) {
5199       /*
5200        * Egraph conflict:
5201        * the conflict is in egraph->expl_vector, in the form "not (l1 and .... and l_n)"
5202        * we need to turn this into the clause "(not l_1) or ... or (not l_n)"
5203        * and add the end marker.
5204        */
5205       conflict = &egraph->expl_vector;
5206       for (i=0; i<conflict->size; i++) {
5207         conflict->data[i] = not(conflict->data[i]);
5208       }
5209       ivector_push(conflict, null_literal); // end marker
5210       record_theory_conflict(egraph->core, conflict->data);
5211 
5212       egraph->stats.th_conflicts ++;
5213 
5214       return false;
5215     }
5216 
5217 
5218     // To detect equalities propagated from the theory solvers (i.e., the simplex
5219     // solver for now).
5220     k = egraph->stack.top;
5221 
5222     // go through all the satellite solvers
5223     for (i=0; i<NUM_SATELLITES; i++) {
5224       if (egraph->ctrl[i] != NULL) {
5225         if (! egraph->ctrl[i]->propagate(egraph->th[i])) {
5226           return false;
5227         }
5228       }
5229     }
5230 
5231 
5232   } while (egraph->stack.top > k);
5233 
5234 
5235   return true;
5236 }
5237 
5238 
5239 
5240 /***************************
5241  *  INTERFACE EQUALITIES   *
5242  **************************/
5243 
5244 /*
5245  * Simpler version of make_eq: does not check whether
5246  * t1 and t2 are known to be equal or distinct.
5247  *
5248  * In particular, this function does not call the theory's check_diseq
5249  * function to avoid circularity.
5250  */
egraph_make_simple_eq(egraph_t * egraph,occ_t t1,occ_t t2)5251 literal_t egraph_make_simple_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
5252   occ_t aux;
5253   eterm_t t;
5254 
5255   assert(t1 != t2);
5256 
5257   // normalize
5258   if (t1 > t2) {
5259     aux = t1; t1 = t2; t2 = aux;
5260   }
5261 
5262   t = egraph_eq_term(egraph, t1, t2);
5263   return egraph_term2literal(egraph, t);
5264 }
5265 
5266 
5267 
5268 /*
5269  * Check whether (eq t1 t2) exists and if it does return the
5270  * corresponding literal.
5271  * - return null_literal if (eq t1 t2) does not exist
5272  * - return false_literal if (eq t1 t2) does exist but is not attached to an atom
5273  */
egraph_find_eq(egraph_t * egraph,occ_t t1,occ_t t2)5274 literal_t egraph_find_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
5275   occ_t aux;
5276   eterm_t eq;
5277   bvar_t v;
5278   literal_t l;
5279 
5280   if (t1 > t2) {
5281     aux = t1; t1 = t2; t2 = aux;
5282   }
5283 
5284   l = null_literal;
5285   eq = egraph_find_eq_term(egraph, t1, t2);
5286   if (eq >= 0) {
5287     assert(egraph_term_type(egraph, eq) == ETYPE_BOOL);
5288     v = egraph->terms.thvar[eq];
5289 #if CONSERVATIVE_DISEQ_AXIOMS
5290     assert(v != null_thvar);
5291     l = pos_lit(v);
5292 #else
5293     // null_thvar is possible if (eq t1 t2) is false at the top level
5294     if (v == null_thvar) {
5295       assert(egraph_term_is_false(egraph, eq) || egraph_term_asserted_false(egraph, eq));
5296       l = false_literal; // eq is asserted as an axiom, so its literal is false
5297     } else {
5298       l = pos_lit(v);
5299     }
5300 #endif
5301   }
5302 
5303   return l;
5304 }
5305 
5306 
5307 
5308 
5309 /**********************
5310  *  HIGH-ORDER TERMS  *
5311  *********************/
5312 
5313 /*
5314  * Check whether child i of p is a function
5315  */
composite_child_is_function(egraph_t * egraph,composite_t * cmp,uint32_t i)5316 static inline bool composite_child_is_function(egraph_t *egraph, composite_t *cmp, uint32_t i) {
5317   return egraph_term_is_function(egraph, term_of_occ(composite_child(cmp, i)));
5318 }
5319 
5320 /*
5321  * Check whether one child of p is a function:
5322  * - scan children from i to p's arity (i=0 or i=1 to skip the first child)
5323  */
composite_has_function_child(egraph_t * egraph,composite_t * cmp,uint32_t i)5324 static bool composite_has_function_child(egraph_t *egraph, composite_t *cmp, uint32_t i) {
5325   uint32_t n;
5326 
5327   n = composite_arity(cmp);
5328   while (i < n) {
5329     if (composite_child_is_function(egraph, cmp, i)) {
5330       return true;
5331     }
5332     i ++;
5333   }
5334   return false;
5335 }
5336 
5337 /*
5338  * Check whether composite cmp is high order:
5339  * - return true if some of cmp's children are function terms
5340  */
composite_is_high_order(egraph_t * egraph,composite_t * cmp)5341 static bool composite_is_high_order(egraph_t *egraph, composite_t *cmp) {
5342   switch (composite_kind(cmp)) {
5343   case COMPOSITE_APPLY:
5344   case COMPOSITE_UPDATE:
5345     return composite_has_function_child(egraph, cmp, 1);
5346   case COMPOSITE_TUPLE:
5347     return composite_has_function_child(egraph, cmp, 0);
5348   case COMPOSITE_EQ:
5349     // (eq u v): both u and v are functions or neither is
5350     return composite_child_is_function(egraph, cmp, 0);
5351   case COMPOSITE_ITE:
5352     // (ite c u v): both u and v are functions or neither is
5353     return composite_child_is_function(egraph, cmp, 1);
5354   case COMPOSITE_DISTINCT:
5355     // (distinct u_1 ... u_n) all children are functions or none
5356     return composite_child_is_function(egraph, cmp, 0);
5357   case COMPOSITE_OR:
5358   default:
5359     return false;
5360   }
5361 }
5362 
5363 
5364 /*
5365  * Check whether there's a high order term in the egraph
5366  */
egraph_has_high_order_terms(egraph_t * egraph)5367 static bool egraph_has_high_order_terms(egraph_t *egraph) {
5368   composite_t *cmp;
5369   uint32_t i, n;
5370 
5371   n = egraph_num_terms(egraph);
5372   for (i=0; i<n; i++) {
5373     cmp = egraph_term_body(egraph, i);
5374     if (composite_body(cmp) && composite_is_high_order(egraph, cmp)) {
5375       return true;
5376     }
5377   }
5378   return false;
5379 }
5380 
5381 
5382 /*
5383  * Check for high-order terms then cache the result in egraph->is_high_order
5384  */
egraph_is_high_order(egraph_t * egraph)5385 static bool egraph_is_high_order(egraph_t *egraph) {
5386   bool h;
5387 
5388   h = egraph->is_high_order;
5389   if (!h) {
5390     h = egraph_has_high_order_terms(egraph);
5391     egraph->is_high_order = h;
5392   }
5393   return h;
5394 }
5395 
5396 
5397 
5398 
5399 /******************************************************************
5400  *  MODIFY THE EGRAPH TO MINIMIZE THE NUMBER OF INTERFACE LEMMAS  *
5401  *****************************************************************/
5402 
5403 /*
5404  * Prepare the satellite models for the arithmetic and bitvector theories
5405  */
egraph_prepare_models(egraph_t * egraph)5406 static void egraph_prepare_models(egraph_t *egraph) {
5407   if (egraph->ctrl[ETYPE_REAL] != NULL) {
5408     assert(egraph->eg[ETYPE_REAL] != NULL);
5409     egraph->eg[ETYPE_REAL]->prepare_model(egraph->th[ETYPE_REAL]);
5410   }
5411   if (egraph->ctrl[ETYPE_BV] != NULL) {
5412     assert(egraph->eg[ETYPE_BV] != NULL);
5413     egraph->eg[ETYPE_BV]->prepare_model(egraph->th[ETYPE_BV]);
5414   }
5415 }
5416 
5417 
5418 /*
5419  * Release the satellite models
5420  */
egraph_release_models(egraph_t * egraph)5421 static void egraph_release_models(egraph_t *egraph) {
5422   if (egraph->ctrl[ETYPE_REAL] != NULL) {
5423     assert(egraph->eg[ETYPE_REAL] != NULL);
5424     egraph->eg[ETYPE_REAL]->release_model(egraph->th[ETYPE_REAL]);
5425   }
5426   if (egraph->ctrl[ETYPE_BV] != NULL) {
5427     assert(egraph->eg[ETYPE_BV] != NULL);
5428     egraph->eg[ETYPE_BV]->release_model(egraph->th[ETYPE_BV]);
5429   }
5430 }
5431 
5432 
5433 
5434 #if TRACE_FCHECK
5435 /*
5436  * Test: check whether there are duplicates in vector v
5437  */
check_interface_duplicates(ivector_t * v)5438 static void check_interface_duplicates(ivector_t *v) {
5439   uint32_t i, j, n;
5440   occ_t t1, t2;
5441 
5442   n = v->size;
5443   for (i=0; i<n; i += 2) {
5444     t1 = v->data[i];
5445     t2 = v->data[i+1];
5446     for (j=i+2; j<n; j += 2) {
5447       if ((v->data[j] == t1 && v->data[j+1] == t2)
5448           || (v->data[j] == t2 && v->data[j+1] == t1)) {
5449         printf("---> EGRAPH: interface lemma duplicate: "
5450                "v[%"PRIu32", %"PRIu32"] = (%"PRId32", %"PRId32"); "
5451                "v[%"PRIu32", %"PRIu32"] = (%"PRId32", %"PRId32")\n", i, i+1, t1, t2, j, j+1, v->data[j], v->data[j+1]);
5452         fflush(stdout);
5453       }
5454     }
5455   }
5456 }
5457 
5458 #endif
5459 
5460 
5461 /*
5462  * Generate interface lemmas for pairs of term occurrences stored in v
5463  * - stop as soon as max_eqs interface lemmas are produced
5464  * - return the number of lemmas generated
5465  */
egraph_gen_interface_lemmas(egraph_t * egraph,uint32_t max_eqs,ivector_t * v)5466 static uint32_t egraph_gen_interface_lemmas(egraph_t *egraph, uint32_t max_eqs, ivector_t *v) {
5467   void *satellite;
5468   th_egraph_interface_t *interface;
5469   uint32_t i, n;
5470   occ_t t1, t2;
5471   thvar_t x1, x2;
5472   literal_t eq;
5473 
5474 #if TRACE_FCHECK
5475   check_interface_duplicates(v);
5476 #endif
5477 
5478   n = v->size;
5479   assert(n > 0);
5480   if (n > 2 * max_eqs) {
5481     n = 2 * max_eqs;
5482   }
5483 
5484   for (i=0; i<n; i += 2) {
5485     t1 = v->data[i];
5486     t2 = v->data[i+1];
5487     assert(egraph_class(egraph, t1) != egraph_class(egraph, t2));
5488     x1 = egraph_base_thvar(egraph, t1);
5489     x2 = egraph_base_thvar(egraph, t2);
5490     assert(x1 != null_thvar && x2 != null_thvar);
5491 
5492     switch (egraph_type(egraph, t1)) {
5493     case ETYPE_INT:
5494     case ETYPE_REAL:
5495       satellite = egraph->th[ETYPE_REAL];
5496       interface = egraph->eg[ETYPE_REAL];
5497       break;
5498 
5499     case ETYPE_BV:
5500       satellite = egraph->th[ETYPE_BV];
5501       interface = egraph->eg[ETYPE_BV];
5502       break;
5503 
5504     default:
5505       assert(false);
5506       abort();
5507       break;
5508     }
5509 
5510     assert(interface->equal_in_model(satellite, x1, x2));
5511     eq = egraph_make_simple_eq(egraph, t1, t2);
5512     interface->gen_interface_lemma(satellite, not(eq), x1, x2, true);
5513   }
5514 
5515   assert(n/2 <= max_eqs);
5516 
5517   return n/2;
5518 }
5519 
5520 /*
5521  * Check whether Boolean variables x1 and x2 have different values in the core
5522  */
bool_var_equal_in_model(egraph_t * egraph,thvar_t x1,thvar_t x2)5523 static bool bool_var_equal_in_model(egraph_t *egraph, thvar_t x1, thvar_t x2) {
5524   bval_t b1, b2;
5525 
5526   b1 = bvar_value(egraph->core, x1);
5527   b2 = bvar_value(egraph->core, x2);
5528   assert(bval_is_def(b1) && bval_is_def(b2));
5529   return b1 == b2;
5530 }
5531 
5532 /*
5533  * Check whether x1 and x2 have different values in the relevant theory solver
5534  * - i = type of x1
5535  * - we ignore the function solver here
5536  */
diseq_in_model(egraph_t * egraph,etype_t i,thvar_t x1,thvar_t x2)5537 static bool diseq_in_model(egraph_t *egraph, etype_t i, thvar_t x1, thvar_t x2) {
5538   switch (i) {
5539   case ETYPE_INT:
5540   case ETYPE_REAL:
5541   case ETYPE_BV:
5542     return !egraph->eg[i]->equal_in_model(egraph->th[i], x1, x2);
5543 
5544   case ETYPE_BOOL:
5545     return  !bool_var_equal_in_model(egraph, x1, x2);;
5546 
5547   default:
5548     return false;
5549   }
5550 }
5551 
5552 
5553 /*
5554  * Check whether the classes of t1 and t2 can be merged
5555  * - c1 must be the class of t1 and c2 must be the class of t2
5556  * - if c1 and c2 have theory variables, then they can be merged if the
5557  *   variables have equal values in the theory model
5558  */
mergeable_classes(egraph_t * egraph,occ_t t1,occ_t t2,class_t c1,class_t c2)5559 static bool mergeable_classes(egraph_t *egraph, occ_t t1, occ_t t2, class_t c1, class_t c2) {
5560   uint32_t msk;
5561   composite_t *cmp;
5562   thvar_t x1, x2;
5563 
5564   if (egraph_opposite_occ(egraph, t1, t2)) {
5565     return false;
5566   }
5567 
5568   assert(c1 != c2);
5569 
5570   msk = egraph->classes.dmask[c1] & egraph->classes.dmask[c2];
5571   if (msk != 0) {
5572     return false;
5573   }
5574 
5575   cmp = congruence_table_find_eq(&egraph->ctable, t1, t2, egraph->terms.label);
5576   if (cmp != NULL && egraph_occ_is_false(egraph, pos_occ(cmp->id))) {
5577     return false;
5578   }
5579 
5580   x1 = egraph_class_thvar(egraph, c1);
5581   x2 = egraph_class_thvar(egraph, c2);
5582 
5583   if (x1 != null_thvar && x2 != null_thvar &&
5584       diseq_in_model(egraph, egraph_class_type(egraph, c1), x1, x2)) {
5585     return false;
5586   }
5587 
5588   return true;
5589 }
5590 
5591 
5592 /*
5593  * Propagate equality v1 == v2 during reconciliation
5594  * - id = edge that caused merging of c1 and c2
5595  */
reconcile_thvar(egraph_t * egraph,class_t c1,thvar_t v1,class_t c2,thvar_t v2,int32_t id)5596 static void reconcile_thvar(egraph_t *egraph, class_t c1, thvar_t v1, class_t c2, thvar_t v2, int32_t id) {
5597   etype_t i;
5598 
5599   assert(v1 != null_thvar && v2 != null_thvar &&
5600          v1 == egraph_class_thvar(egraph, c1) &&
5601          v2 == egraph_class_thvar(egraph, c2));
5602 
5603   i = egraph->classes.etype[c1];
5604 
5605   switch (i) {
5606   case ETYPE_INT:
5607   case ETYPE_REAL:
5608   case ETYPE_BV:
5609     assert(egraph->eg[i]->equal_in_model(egraph->th[i], v1, v2));
5610     break;
5611 
5612   case ETYPE_FUNCTION:
5613     egraph->eg[i]->assert_equality(egraph->th[i], v1, v2, id);
5614     break;
5615 
5616   case ETYPE_BOOL:
5617     // all Boolean variables are already assigned in the core.
5618     assert(bool_var_equal_in_model(egraph, v1, v2));
5619     break;
5620 
5621   case ETYPE_TUPLE:
5622     propagate_tuple_equality(egraph, v1, v2);
5623     break;
5624 
5625   default:
5626     assert(false);
5627   }
5628 }
5629 
5630 
5631 /*
5632  * Attempt to merge the classes of t1 and t2 without affecting the theory models
5633  * - t1 and t2 must not be Boolean
5634  * - i = corresponding edge id
5635  * - return true if t1 and t2 can be merged
5636  * - return false otherwise
5637  */
test_merge(egraph_t * egraph,occ_t t1,occ_t t2,int32_t i)5638 static bool test_merge(egraph_t *egraph, occ_t t1, occ_t t2, int32_t i) {
5639   use_vector_t *v;
5640   composite_t *p;
5641   class_t c1, c2;
5642   int32_t aux;
5643   uint32_t j, n;
5644   elabel_t l;
5645   occ_t t;
5646   thvar_t v1, v2;
5647 
5648   if (egraph_equal_occ(egraph, t1, t2)) {
5649     return true;
5650   }
5651 
5652   c1 = egraph_class(egraph, t1);
5653   c2 = egraph_class(egraph, t2);
5654 
5655   if (! mergeable_classes(egraph, t1, t2, c1, c2)) {
5656     return false;
5657   }
5658 
5659   assert(c1 != c2 && (egraph->classes.dmask[c1] & egraph->classes.dmask[c2]) == 0);
5660 
5661   // make sure c2 is the class with smallest parent vector
5662   if (egraph_class_nparents(egraph, c2) > egraph_class_nparents(egraph, c1)) {
5663     aux = t1; t1 = t2; t2 = aux;
5664     aux = c1; c1 = c2; c2 = aux;
5665   }
5666 
5667   // save t2 and its label for backtracking
5668   undo_stack_push_merge(&egraph->undo, t2, egraph_label(egraph, t2));
5669 
5670   // update the explanation tree
5671   invert_branch(egraph, t2);
5672   assert(egraph->terms.edge[term_of_occ(t2)] == null_edge);
5673   egraph->terms.edge[term_of_occ(t2)] = i;
5674 
5675   // remove c2's parents from the congruence table
5676   v = egraph->classes.parents + c2;
5677   n = v->last;
5678   for (j=0; j<n; j++) {
5679     p  = v->data[j];
5680     if (valid_entry(p)) {
5681       // p is in the congruence table
5682       congruence_table_remove(&egraph->ctable, p);
5683       // remove p from the parent vectors (except v)
5684       separate_composite(p, egraph->terms.label, egraph->classes.parents, c2);
5685       assert(v->data[j] == p);
5686     }
5687   }
5688 
5689   // assign a new label to all terms in t2's class
5690   l = egraph_label(egraph, t1);
5691   t = t2;
5692   do {
5693     egraph_set_label(egraph, t, l);
5694     t = egraph_next(egraph, t);
5695     assert(term_of_occ(t) != term_of_occ(t2) || t == t2);
5696   } while (t != t2);
5697 
5698   // update dmask of c1
5699   egraph->classes.dmask[c1] |= egraph->classes.dmask[c2];
5700 
5701   //  merge lists of terms: swap next[t1] and next[t2]
5702   t = egraph_next(egraph, t2);
5703   egraph_set_next(egraph, t2, egraph_next(egraph, t1));
5704   egraph_set_next(egraph, t1, t);
5705 
5706   // reprocess all the composites in v
5707   for (j=0; j<n; j++) {
5708     p = v->data[j];
5709     if (valid_entry(p)) {
5710       if (composite_simplifies(egraph, p)) {
5711         // p no longer a congruence root: put a mark for backtracking
5712         mark_use_vector_entry(v, j);
5713       } else {
5714         // put p back into the use vectors: this add p to c's parent
5715         attach_composite(p, egraph->terms.label, egraph->classes.parents);
5716       }
5717     }
5718   }
5719 
5720   /*
5721    * deal with the theory variables of c1 and c2:
5722    */
5723   v2 = egraph->classes.thvar[c2];
5724   v1 = egraph->classes.thvar[c1];
5725   if (v1 != null_thvar) {
5726     assert(v2 != null_thvar);
5727     reconcile_thvar(egraph, c1, v1, c2, v2, i);
5728   }
5729 
5730   return true;
5731 }
5732 
5733 
5734 
5735 /*
5736  * Backtrack if a reconciliation attempt fails:
5737  * - k = top of the undo queue when the EXPL_RECONCILE edge was added
5738  *   (so this revert all merges in undo[k ... top-1]
5739  */
egraph_undo_reconcile_attempt(egraph_t * egraph,uint32_t k)5740 static void egraph_undo_reconcile_attempt(egraph_t *egraph, uint32_t k) {
5741   uint32_t i;
5742   unsigned char *utag;
5743   undo_t *udata;
5744 
5745   assert(k <= egraph->undo.top);
5746 
5747   i = egraph->undo.top;
5748   utag = egraph->undo.tag;
5749   udata = egraph->undo.data;
5750 
5751   while (i > k) {
5752     i --;
5753     switch (utag[i]) {
5754     case UNDO_MERGE:
5755       undo_merge(egraph, udata[i].merge.saved_occ, udata[i].merge.saved_label);
5756       break;
5757 
5758     case UNDO_SIMPLIFY:
5759       restore_composite(egraph, udata[i].ptr);
5760       break;
5761 
5762     case UNDO_DISTINCT:
5763       assert(false); // should not happen
5764       undo_distinct(egraph);
5765       break;
5766 
5767     // store terms to reanalyze into reanalyze_vector
5768     case REANALYZE_CONGRUENCE_ROOT:
5769       deactivate_congruence_root(egraph, udata[i].ptr);
5770       pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
5771       break;
5772 
5773     case REANALYZE_COMPOSITE:
5774       pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
5775       break;
5776 
5777     default:
5778       assert(false);
5779       break;
5780     }
5781   }
5782 
5783   assert(i == k);
5784   egraph->undo.top = k;
5785 }
5786 
5787 
5788 
5789 /*
5790  * Collect an interface equality (t1 == t2) when reconciliation fails
5791  * - source = edge that started the reconciliation
5792  * - i = conflict edge
5793  */
collect_interface_pair(egraph_t * egraph,int32_t source,int32_t i)5794 static void collect_interface_pair(egraph_t *egraph, int32_t source, int32_t i) {
5795   equeue_elem_t *e;
5796   ivector_t *v;
5797   int32_t k;
5798 
5799   k = egraph_get_reconcile_edge(egraph, source, i);
5800   e = egraph->stack.eq + k;
5801 
5802   v = &egraph->interface_eqs;
5803   ivector_push(v, e->lhs);
5804   ivector_push(v, e->rhs);
5805 }
5806 
5807 
5808 /*
5809  * Propagate equalities during reconciliation
5810  */
egraph_prop_reconcile(egraph_t * egraph)5811 static bool egraph_prop_reconcile(egraph_t *egraph) {
5812   equeue_elem_t *e;
5813   uint32_t i, s;
5814 
5815   i = egraph->stack.prop_ptr;
5816   s = i;
5817   while (i < egraph->stack.top) {
5818     e = egraph->stack.eq + i;
5819     if (!test_merge(egraph, e->lhs, e->rhs, i)) {
5820       collect_interface_pair(egraph, s, i);
5821       return false;
5822     }
5823     i ++;
5824   }
5825   egraph->stack.prop_ptr = i;
5826 
5827   return true;
5828 }
5829 
5830 
5831 /*
5832  * Attempt to make t1 and t2 equal in the egraph then propagate
5833  * - return false if that leads to a conflict
5834  * - return true otherwise
5835  */
egraph_reconcile_pair(egraph_t * egraph,occ_t t1,occ_t t2)5836 static bool egraph_reconcile_pair(egraph_t *egraph, occ_t t1, occ_t t2) {
5837   int32_t k;
5838   uint32_t top;
5839 
5840   assert(egraph->stack.prop_ptr == egraph->stack.top);
5841 
5842   if (egraph_equal_occ(egraph, t1, t2)) {
5843     return true;  // already equal: nothing to do
5844   }
5845 
5846   top = egraph->undo.top;
5847   k = egraph_stack_push_eq(&egraph->stack, t1, t2);
5848   assert(k == egraph->stack.prop_ptr);
5849 
5850   egraph->stack.etag[k] = EXPL_RECONCILE;
5851   if (egraph_prop_reconcile(egraph)) {
5852     return true;
5853   }
5854 
5855   // clean up
5856   egraph_undo_reconcile_attempt(egraph, top);
5857   egraph->stack.top = k;
5858   egraph->stack.prop_ptr = k;
5859   return false;
5860 }
5861 
5862 
5863 /*
5864  * Process a class of terms
5865  * - every element of v is a variable in a theory solver
5866  * - solver = the theory solver for v
5867  * - eg = the egraph interface for that solver
5868  */
egraph_reconcile_class(egraph_t * egraph,int32_t * v,void * solver,th_egraph_interface_t * eg)5869 static bool egraph_reconcile_class(egraph_t *egraph, int32_t *v, void *solver, th_egraph_interface_t *eg) {
5870   uint32_t i, n;
5871   eterm_t t1, t2;
5872 
5873   n = iv_size(v);
5874   assert(n >= 2);
5875 
5876   t1 = eg->eterm_of_var(solver, v[0]);
5877   for (i=1; i<n; i++) {
5878     t2 = eg->eterm_of_var(solver, v[i]);
5879     if (!egraph_reconcile_pair(egraph, pos_occ(t1), pos_occ(t2))) {
5880 #if 0
5881       printf("Reconciliation failed for class with %"PRIu32" elements, at element %"PRIu32"\n", n, i);
5882 #endif
5883       return false;
5884     }
5885   }
5886 
5887   return true;
5888 }
5889 
5890 
5891 /*
5892  * Process a term partition
5893  * - return true if all terms of every class in the partition can be reconciled
5894  * - return false otherwise
5895  */
egraph_reconcile_partition(egraph_t * egraph,ipart_t * partition,void * solver,th_egraph_interface_t * eg)5896 static bool egraph_reconcile_partition(egraph_t *egraph, ipart_t *partition, void *solver, th_egraph_interface_t *eg) {
5897   int32_t *v;
5898   uint32_t i, n;
5899   bool reconciled;
5900 
5901   reconciled = true;
5902   n = int_partition_nclasses(partition);
5903   for (i=0; i<n; i++) {
5904     v = partition->classes[i];
5905     reconciled &= egraph_reconcile_class(egraph, v, solver, eg);
5906   }
5907 
5908   return reconciled;
5909 }
5910 
5911 
5912 
5913 /*
5914  * Try model reconciliation: return true if that worked, false otherwise
5915  * - if the result is false then candidates for interface lemmas are
5916  *   stored in egraph->interface_eqs.
5917  */
egraph_reconcile(egraph_t * egraph)5918 static bool egraph_reconcile(egraph_t *egraph) {
5919   ipart_t *partition;
5920   bool reconciled;
5921 
5922   reconciled = true;
5923 
5924   if (egraph->ctrl[ETYPE_REAL] != NULL) {
5925     partition = egraph->eg[ETYPE_REAL]->build_model_partition(egraph->th[ETYPE_REAL]);
5926     reconciled = egraph_reconcile_partition(egraph, partition, egraph->th[ETYPE_REAL], egraph->eg[ETYPE_REAL]);
5927     egraph->eg[ETYPE_REAL]->release_model_partition(egraph->th[ETYPE_REAL], partition);
5928   }
5929 
5930   if (egraph->ctrl[ETYPE_BV] != NULL) {
5931     partition = egraph->eg[ETYPE_BV]->build_model_partition(egraph->th[ETYPE_BV]);
5932     reconciled &= egraph_reconcile_partition(egraph, partition, egraph->th[ETYPE_BV], egraph->eg[ETYPE_BV]);
5933     egraph->eg[ETYPE_BV]->release_model_partition(egraph->th[ETYPE_BV], partition);
5934   }
5935 
5936   return reconciled;
5937 }
5938 
5939 
5940 
5941 /*
5942  * Prepare for reconciliation:
5943  * - store the current number of equalities + the top of the undo stack
5944  * - set the reconcile_mode flag
5945  */
egraph_start_reconciliation(egraph_t * egraph)5946 static void egraph_start_reconciliation(egraph_t *egraph) {
5947   assert(egraph->stack.prop_ptr == egraph->stack.top);
5948   egraph->reconcile_top = egraph->undo.top;
5949   egraph->reconcile_neqs = egraph->stack.top;
5950   egraph->reconcile_mode = true;
5951 }
5952 
5953 
5954 /*
5955  * Restore the egraph state to what it was before reconciliation:
5956  */
egraph_reconciliation_restore(egraph_t * egraph)5957 static void egraph_reconciliation_restore(egraph_t *egraph) {
5958   egraph_undo_reconcile_attempt(egraph, egraph->reconcile_top);
5959   egraph->stack.top = egraph->reconcile_neqs;
5960   egraph->stack.prop_ptr = egraph->reconcile_neqs;
5961   egraph->reconcile_mode = false;
5962 }
5963 
5964 
5965 
5966 
5967 
5968 /*****************
5969  *  FINAL CHECK  *
5970  ****************/
5971 
5972 /*
5973  * BASELINE VERSION OF FINAL CHECK
5974  * - call final_check on all satellites then use the reconcile_model
5975  *   function in each solver
5976  */
baseline_final_check(egraph_t * egraph)5977 static fcheck_code_t baseline_final_check(egraph_t *egraph) {
5978   fcheck_code_t c;
5979   uint32_t i, max_eq;
5980 
5981 #if TRACE_FCHECK
5982   printf("---> EGRAPH: final check (baseline)\n\n");
5983   print_egraph_terms(stdout, egraph);
5984   printf("\n");
5985   print_egraph_root_classes_details(stdout, egraph);
5986   fflush(stdout);
5987 #endif
5988 
5989   if (egraph->ctrl[ETYPE_REAL] != NULL) {
5990     // arithmetic solver
5991     c = egraph->ctrl[ETYPE_REAL]->final_check(egraph->th[ETYPE_REAL]);
5992     if (c != FCHECK_SAT) {
5993 #if TRACE_FCHECK
5994       printf("---> exit at arith final check\n");
5995       fflush(stdout);
5996 #endif
5997       return c;
5998     }
5999   }
6000 
6001   if (egraph->ctrl[ETYPE_BV] != NULL) {
6002     // bitvector solver
6003     c = egraph->ctrl[ETYPE_BV]->final_check(egraph->th[ETYPE_BV]);
6004     if (c != FCHECK_SAT) {
6005 #if TRACE_FCHECK
6006        printf("---> exit at bv final check\n");
6007        fflush(stdout);
6008 #endif
6009       return c;
6010     }
6011   }
6012 
6013   if (egraph->ctrl[ETYPE_FUNCTION] != NULL) {
6014     // array solver
6015     c = egraph->ctrl[ETYPE_FUNCTION]->final_check(egraph->th[ETYPE_FUNCTION]);
6016     if (c != FCHECK_SAT) {
6017 #if TRACE_FCHECK
6018       printf("---> exit at array final check\n");
6019       fflush(stdout);
6020 #endif
6021       return c;
6022     }
6023   }
6024 
6025 
6026   // i = number of interface equalities generated
6027   // max_eq = bound on number of interface equalities
6028   max_eq = egraph->max_interface_eqs;
6029   i = 0;
6030   assert(i < max_eq);
6031 
6032   if (egraph->ctrl[ETYPE_REAL] != NULL) {
6033     // reconcile for arithmetic solver
6034     assert(egraph->eg[ETYPE_REAL] != NULL);
6035     i = egraph->eg[ETYPE_REAL]->reconcile_model(egraph->th[ETYPE_REAL], max_eq);
6036   }
6037 
6038   if (i < max_eq && egraph->ctrl[ETYPE_BV] != NULL) {
6039     // reconcile in bitvector solver
6040     assert(egraph->eg[ETYPE_BV] != NULL);
6041     i += egraph->eg[ETYPE_BV]->reconcile_model(egraph->th[ETYPE_BV], max_eq - i);
6042   }
6043 
6044 #if TRACE_FCHECK
6045   if (i > 0) {
6046     printf("---> %"PRIu32" interface lemmas from bv/arith solvers\n", i);
6047     fflush(stdout);
6048   }
6049 #endif
6050 
6051   if (i == 0 && egraph->ctrl[ETYPE_FUNCTION] != NULL && egraph_is_high_order(egraph)) {
6052     /*
6053      * reconcile for array solver: do it only if bv and arith models
6054      * are consistent with the egraph. Also there's nothing to do
6055      * if there are no high-order terms.
6056      */
6057     assert(egraph->eg[ETYPE_FUNCTION] != NULL);
6058     i = egraph->eg[ETYPE_FUNCTION]->reconcile_model(egraph->th[ETYPE_FUNCTION], 1);
6059 #if TRACE_CHECK
6060     if (i > 0) {
6061       printf("---> %"PRIu32" interface lemmas from array solver\n", i);
6062       fflush(stdout);
6063     }
6064 #endif
6065   }
6066 
6067   egraph->stats.interface_eqs += i;
6068 
6069   if (i == 1) {
6070     trace_printf(egraph->core->trace, 3, "(final check: 1 interface lemma)\n");
6071   } else {
6072     trace_printf(egraph->core->trace, 3, "(final check: %"PRIu32" interface lemmas)\n", i);
6073   }
6074 
6075   c = FCHECK_SAT; // default value
6076   if (i > 0) {
6077     c = FCHECK_CONTINUE;
6078   }
6079 
6080   return c;
6081 }
6082 
6083 
6084 /*
6085  * New: experimental version
6086  */
experimental_final_check(egraph_t * egraph)6087 static fcheck_code_t experimental_final_check(egraph_t *egraph) {
6088   fcheck_code_t c;
6089   uint32_t i, max_eqs;
6090 
6091 #if TRACE_FCHECK
6092   printf("---> EGRAPH: final check (experimental)\n\n");
6093   print_egraph_terms(stdout, egraph);
6094   printf("\n\n");
6095   print_egraph_root_classes_details(stdout, egraph);
6096   fflush(stdout);
6097 #endif
6098 
6099   if (egraph->ctrl[ETYPE_REAL] != NULL) {
6100     c = egraph->ctrl[ETYPE_REAL]->final_check(egraph->th[ETYPE_REAL]);
6101     if (c != FCHECK_SAT) {
6102 #if TRACE_FCHECK
6103       printf("---> exit at arith final check\n");
6104       fflush(stdout);
6105 #endif
6106       return c;
6107     }
6108   }
6109 
6110   if (egraph->ctrl[ETYPE_BV] != NULL) {
6111     // bitvector solver
6112     c = egraph->ctrl[ETYPE_BV]->final_check(egraph->th[ETYPE_BV]);
6113     if (c != FCHECK_SAT) {
6114 #if TRACE_FCHECK
6115       printf("---> exit at bv final check\n");
6116       fflush(stdout);
6117 #endif
6118       return c;
6119     }
6120   }
6121 
6122 
6123   /*
6124    * Try egraph reconciliation
6125    */
6126   c = FCHECK_SAT;
6127   egraph_prepare_models(egraph);
6128   egraph_start_reconciliation(egraph);
6129 
6130   if (! egraph_reconcile(egraph)) {
6131     egraph_reconciliation_restore(egraph);
6132 
6133     max_eqs = egraph->max_interface_eqs;
6134 
6135     // Generate interface equalities
6136     i = egraph_gen_interface_lemmas(egraph, max_eqs, &egraph->interface_eqs);
6137 
6138     egraph->stats.interface_eqs += i;
6139     ivector_reset(&egraph->interface_eqs);
6140     c = FCHECK_CONTINUE;
6141 
6142     if (i == 1) {
6143       trace_printf(egraph->core->trace, 3, "(final check: 1 interface lemma)\n");
6144     } else {
6145       trace_printf(egraph->core->trace, 3, "(final check: %"PRIu32" interface lemmas)\n", i);
6146     }
6147 
6148 #if TRACE_FCHECK
6149     printf("---> egraph reconcile failed: %"PRIu32" interface lemmas\n", i);
6150     fflush(stdout);
6151 #endif
6152 
6153 
6154   } else if (egraph->ctrl[ETYPE_FUNCTION] != NULL) {
6155 #if TRACE_FCHECK
6156     printf("---> EGRAPH: final check: after reconcile\n\n");
6157     print_egraph_terms(stdout, egraph);
6158     printf("\n\n");
6159     print_egraph_root_classes_details(stdout, egraph);
6160     fflush(stdout);
6161 #endif
6162     /*
6163      * bv/arith models are consistent with the egraph:
6164      * deal with the array solver
6165      */
6166     c = egraph->ctrl[ETYPE_FUNCTION]->final_check(egraph->th[ETYPE_FUNCTION]);
6167     if (c == FCHECK_SAT) {
6168       if (egraph_is_high_order(egraph)) {
6169         i = egraph->eg[ETYPE_FUNCTION]->reconcile_model(egraph->th[ETYPE_FUNCTION], 1);
6170         if (i > 0) {
6171 #if TRACE_FCHECK
6172           printf("---> exit after array reconcile: %"PRIu32" lemmas\n", i);
6173           fflush(stdout);
6174 #endif
6175           trace_printf(egraph->core->trace, 3, "(final check: %"PRIu32" array lemmas)\n", i);
6176           c = FCHECK_CONTINUE;
6177         }
6178       }
6179     } else {
6180 #if TRACE_FCHECK
6181       printf("---> exit at array final check\n");
6182       fflush(stdout);
6183 #endif
6184     }
6185 
6186     if (c != FCHECK_SAT) {
6187       egraph_reconciliation_restore(egraph);
6188     }
6189   }
6190 
6191   egraph_release_models(egraph);
6192 
6193   return c;
6194 }
6195 
6196 
6197 /*
6198  * Call final check for all the satellite solvers
6199  * If all return SAT, try to build consistent models
6200  * If models are not consistent, generate interface equalities
6201  */
_o_egraph_final_check(egraph_t * egraph)6202 fcheck_code_t _o_egraph_final_check(egraph_t *egraph) {
6203   egraph->stats.final_checks ++;
6204 
6205   if (egraph_option_disabled(egraph, EGRAPH_OPTIMISTIC_FCHECK)) {
6206     return baseline_final_check(egraph);
6207   } else {
6208     return experimental_final_check(egraph);
6209   }
6210 }
6211 
egraph_final_check(egraph_t * egraph)6212 fcheck_code_t egraph_final_check(egraph_t *egraph) {
6213   MT_PROTECT(fcheck_code_t, __yices_globals.lock, _o_egraph_final_check(egraph));
6214 }
6215 
6216 
6217 /*
6218  * Clear the edges added during reconciliation:
6219  * - if egraph_final_check succeeds, then we may have added new equalities
6220  *   in the egraph (during model reconciliation).
6221  * - before any other operation on the egraph (e.g., assert, push, pop), we
6222  *   must restore it to what it was at the start of final check
6223  */
egraph_clear(egraph_t * egraph)6224 void egraph_clear(egraph_t *egraph) {
6225   uint32_t i;
6226 
6227   if (egraph->reconcile_mode) {
6228     egraph_reconciliation_restore(egraph);
6229   }
6230   // forward to the satellite solvers
6231   for (i=0; i<NUM_SATELLITES; i++) {
6232     if (egraph->ctrl[i] != NULL) {
6233       egraph->ctrl[i]->clear(egraph->th[i]);
6234     }
6235   }
6236 }
6237 
6238 
6239 
6240 /****************
6241  *  ASSERTIONS  *
6242  ***************/
6243 
6244 /*
6245  * Assert (t == true) with explanation l
6246  * - term_of_occ(t) must be a boolean term
6247  */
egraph_assert_term(egraph_t * egraph,occ_t t,literal_t l)6248 void egraph_assert_term(egraph_t *egraph, occ_t t, literal_t l) {
6249   int32_t k;
6250 
6251 #if TRACE
6252   printf("---> EGRAPH: Asserting term ");
6253   print_occurrence(stdout, t);
6254   printf(", expl = ");
6255   print_literal(stdout, l);
6256   printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6257   if (egraph_term_is_composite(egraph, term_of_occ(t))) {
6258     printf("---> ");
6259     print_eterm_def(stdout, egraph, term_of_occ(t));
6260   }
6261   if (egraph_occ_is_true(egraph, t)) {
6262     printf("---> EGRAPH: Term ");
6263     print_occurrence(stdout, t);
6264     printf(" is already true\n");
6265   }
6266 #endif
6267 
6268   // don't do anything if t is already true
6269   if (! egraph_occ_is_true(egraph, t)) {
6270     k = egraph_stack_push_eq(&egraph->stack, t, true_occ);
6271     egraph->stack.etag[k] = EXPL_ASSERT;
6272     egraph->stack.edata[k].lit = l;
6273   }
6274 }
6275 
6276 /*
6277  * Assert (t1 == t2) with explanation l
6278  */
egraph_assert_eq(egraph_t * egraph,occ_t t1,occ_t t2,literal_t l)6279 void egraph_assert_eq(egraph_t *egraph, occ_t t1, occ_t t2, literal_t l) {
6280   int32_t k;
6281 
6282 #if TRACE
6283   printf("---> EGRAPH: Asserting ");
6284   print_occurrence(stdout, t1);
6285   printf(" == ");
6286   print_occurrence(stdout, t2);
6287   printf(" , expl = ");
6288   print_literal(stdout, l);
6289   printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6290   if (egraph_equal_occ(egraph, t1, t2)) {
6291     printf("---> EGRAPH: ");
6292     print_occurrence(stdout, t1);
6293     printf(" and ");
6294     print_occurrence(stdout, t2);
6295     printf(" are already equal\n");
6296   }
6297 #endif
6298 
6299   // don't do anything if t1 and t2 are already equal
6300   if (! egraph_equal_occ(egraph, t1, t2)) {
6301     k = egraph_stack_push_eq(&egraph->stack, t1, t2);
6302     egraph->stack.etag[k] = EXPL_ASSERT;
6303     egraph->stack.edata[k].lit = l;
6304   }
6305 }
6306 
6307 
6308 
6309 /*
6310  * Assert atom atm with explanation l (propagation from the core)
6311  * - if l has positive polarity then atom is asserted true
6312  *   if l has negative polarity then atom is asserted false
6313  * - forward to arithmetic or bitvector solver if required
6314  * - return false if there's a conflict, true otherwise
6315  */
egraph_assert_atom(egraph_t * egraph,void * atom,literal_t l)6316 bool egraph_assert_atom(egraph_t *egraph, void *atom, literal_t l) {
6317   atom_t *a;
6318   occ_t t;
6319   bool resu;
6320 
6321   resu = true;
6322 
6323   switch (atom_tag(atom)) {
6324   case EGRAPH_ATM_TAG:
6325     a = (atom_t *) untag_atom(atom);
6326     assert(a->boolvar == var_of(l));
6327     t = mk_occ(a->eterm, sign_of(l));
6328     egraph_assert_term(egraph, t, l);
6329     break;
6330 
6331   case ARITH_ATM_TAG:
6332     resu = egraph->arith_smt->assert_atom(egraph->th[ETYPE_INT], untag_atom(atom), l);
6333     break;
6334 
6335   case BV_ATM_TAG:
6336     resu = egraph->bv_smt->assert_atom(egraph->th[ETYPE_BV], untag_atom(atom), l);
6337     break;
6338   }
6339 
6340   return resu;
6341 }
6342 
6343 
6344 /*
6345  * Assert (t == true) as an axiom
6346  * - axiom assertion is allowed at the base level only
6347  */
egraph_assert_axiom(egraph_t * egraph,occ_t t)6348 void egraph_assert_axiom(egraph_t *egraph, occ_t t) {
6349   int32_t k;
6350 
6351 #if TRACE
6352   printf("---> EGRAPH: Asserting axiom ");
6353   print_occurrence(stdout, t);
6354   printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6355   if (egraph_term_is_composite(egraph, term_of_occ(t))) {
6356     printf("---> ");
6357     print_eterm_def(stdout, egraph, term_of_occ(t));
6358   }
6359 #endif
6360 
6361   assert(egraph->decision_level == egraph->base_level);
6362   k = egraph_stack_push_eq(&egraph->stack, true_occ, t);
6363   egraph->stack.etag[k] = EXPL_AXIOM;
6364 }
6365 
6366 
6367 /*
6368  * Assert (t1 == t2) as an axiom
6369  */
egraph_assert_eq_axiom(egraph_t * egraph,occ_t t1,occ_t t2)6370 void egraph_assert_eq_axiom(egraph_t *egraph, occ_t t1, occ_t t2) {
6371   int32_t k;
6372 
6373 #if TRACE
6374   printf("---> EGRAPH: Asserting axiom ");
6375   print_occurrence(stdout, t1);
6376   printf(" == ");
6377   print_occurrence(stdout, t2);
6378   printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6379 #endif
6380 
6381   assert(egraph->decision_level == egraph->base_level);
6382   k = egraph_stack_push_eq(&egraph->stack, t1, t2);
6383   egraph->stack.etag[k] = EXPL_AXIOM;
6384 }
6385 
6386 
6387 /*
6388  * Assert (t1 != t2) as an axiom
6389  * - create equality atom l --> (eq t1 t2) then assert not(l)
6390  *   in the core
6391  */
egraph_assert_diseq_axiom(egraph_t * egraph,occ_t t1,occ_t t2)6392 void egraph_assert_diseq_axiom(egraph_t *egraph, occ_t t1, occ_t t2) {
6393 #if CONSERVATIVE_DISEQ_AXIOMS
6394   literal_t l;
6395 #else
6396   occ_t eq;
6397   int32_t k;
6398 #endif
6399 
6400 
6401 #if TRACE
6402   printf("---> EGRAPH: Asserting axiom ");
6403   print_occurrence(stdout, t1);
6404   printf(" != ");
6405   print_occurrence(stdout, t2);
6406   printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6407 #endif
6408 
6409   assert(egraph->decision_level == egraph->base_level);
6410 #if CONSERVATIVE_DISEQ_AXIOMS
6411   // conservative approach
6412   l = egraph_make_eq(egraph, t1, t2);
6413   add_unit_clause(egraph->core, not(l));
6414 #else
6415   // avoid creation of an atom: eq has no theory variable attached
6416   eq = egraph_make_eq_term(egraph, t1, t2);
6417   k = egraph_stack_push_eq(&egraph->stack, eq, false_occ);
6418   egraph->stack.etag[k] = EXPL_AXIOM;
6419 #endif
6420 }
6421 
6422 
6423 /*
6424  * Assert (distinct t1 ... tn) as an axiom
6425  */
egraph_assert_distinct_axiom(egraph_t * egraph,uint32_t n,occ_t * t)6426 void egraph_assert_distinct_axiom(egraph_t *egraph, uint32_t n, occ_t *t) {
6427   eterm_t d;
6428   int32_t k;
6429   uint32_t i, j;
6430 
6431   assert(egraph->decision_level == egraph->base_level);
6432   d = egraph_distinct_term(egraph, n, t);
6433   if (d != null_eterm) {
6434     if (egraph_term_is_fresh(egraph, d)) {
6435       egraph_set_term_real_type(egraph, d, bool_type(egraph->types));
6436       egraph_activate_term(egraph, d, ETYPE_BOOL, const_bvar);
6437     }
6438 #if TRACE
6439     printf("---> EGRAPH: Asserting axiom ");
6440     print_composite(stdout, egraph->terms.body[d]);
6441     printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6442 #endif
6443     k = egraph_stack_push_eq(&egraph->stack, pos_occ(d), true_occ);
6444     egraph->stack.etag[k] = EXPL_AXIOM;
6445 
6446   } else {
6447     /*
6448      * Too many distinct terms. Expand into n*(n-1)/2 disequalities
6449      */
6450     for (i=0; i<n-1; i++) {
6451       for (j=i+1; j<n; j++) {
6452         egraph_assert_diseq_axiom(egraph, t[i], t[j]);
6453       }
6454     }
6455   }
6456 }
6457 
6458 
6459 /*
6460  * Assert not (distinct t_1 ... t_n) as an axiom:
6461  * this adds the clause "(eq t_1 t_2) or .... or (eq t_n-1 t_n)" to the core
6462  */
egraph_assert_notdistinct_axiom(egraph_t * egraph,uint32_t n,occ_t * t)6463 void egraph_assert_notdistinct_axiom(egraph_t *egraph, uint32_t n, occ_t *t) {
6464   ivector_t *v;
6465 
6466   assert(egraph->decision_level == egraph->base_level);
6467   v = &egraph->aux_buffer;
6468   expand_distinct(egraph, n, t, v);
6469   add_clause(egraph->core, v->size, v->data);
6470 }
6471 
6472 
6473 /*
6474  * Assert (f a_1 ... a_n) as an axiom
6475  * - build term t := (f a_1 ... a_n) and add const_bvar as its theory variable
6476  * - push equality (t == true)
6477  */
egraph_assert_pred_axiom(egraph_t * egraph,occ_t f,uint32_t n,occ_t * a)6478 void egraph_assert_pred_axiom(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
6479   eterm_t t;
6480   int32_t k;
6481 
6482   t = egraph_apply_term(egraph, f, n, a);
6483   if (egraph_term_is_fresh(egraph, t)) {
6484     /*
6485      * HACK: we attach bool_const as theory variable of t
6486      * but we attach no theory variable to the class of t
6487      * (thvar[t] is used by the ackermann lemma function)
6488      */
6489     egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
6490     egraph_activate_term(egraph, t, ETYPE_BOOL, null_thvar);
6491     egraph->terms.thvar[t] = const_bvar;
6492 
6493   } else if (egraph->terms.thvar[t] == null_thvar) {
6494     egraph->terms.thvar[t] = const_bvar;
6495   }
6496 
6497   k = egraph_stack_push_eq(&egraph->stack, true_occ, pos_occ(t));
6498   egraph->stack.etag[k] = EXPL_AXIOM;
6499 }
6500 
6501 
6502 /*
6503  * Assert not (f t_1 ... t_n) as an axiom:
6504  * build literal l = (f t_1 ... t_n) then assert not l in the core
6505  */
egraph_assert_notpred_axiom(egraph_t * egraph,occ_t f,uint32_t n,occ_t * t)6506 void egraph_assert_notpred_axiom(egraph_t *egraph, occ_t f, uint32_t n, occ_t *t) {
6507   literal_t l;
6508 
6509   l = egraph_make_pred(egraph, f, n, t);
6510   add_unit_clause(egraph->core, not(l));
6511 }
6512 
6513 
6514 
6515 
6516 /******************************************
6517  *  EQUALITY PROPAGATION FROM SATELLITES  *
6518  *****************************************/
6519 
6520 /*
6521  * Propagation from a satellite solver
6522  * - add the equality (t1 == t2) to the propagation queue with explanation expl
6523  * - id = code to identify the satellite solver
6524  *   valid codes are EXPL_ARITH_PROPAGATION, EXPL_BV_PROPAGATION, EXPL_FUN_PROPAGATION
6525  * - expl = whatever the solver needs to explain the equality
6526  */
egraph_propagate_equality(egraph_t * egraph,eterm_t t1,eterm_t t2,expl_tag_t id,void * expl)6527 void egraph_propagate_equality(egraph_t *egraph, eterm_t t1, eterm_t t2, expl_tag_t id, void *expl) {
6528   int32_t k;
6529 
6530   assert((id == EXPL_ARITH_PROPAGATION && egraph_term_is_arith(egraph, t1) &&
6531           egraph_term_is_arith(egraph, t2)) ||
6532          (id == EXPL_BV_PROPAGATION && egraph_term_is_bv(egraph, t1) && egraph_term_is_bv(egraph, t2)) ||
6533          (id == EXPL_FUN_PROPAGATION && egraph_term_is_function(egraph, t1) &&
6534           egraph_term_is_function(egraph, t2)));
6535 
6536   if (egraph_equal_occ(egraph, pos_occ(t1), pos_occ(t2))) {
6537 #if 0
6538     printf("---> EGRAPH: redundant eq prop: g!%"PRId32" == g!%"PRId32"\n", t1, t2);
6539 #endif
6540     // redundant
6541     return;
6542   }
6543 
6544 #if 0
6545   printf("---> EGRAPH: good eq prop: g!%"PRId32" == g!%"PRId32"\n", t1, t2);
6546 #endif
6547   egraph->stats.eq_props ++;
6548 
6549   k = egraph_stack_push_eq(&egraph->stack, pos_occ(t1), pos_occ(t2));
6550   egraph->stack.etag[k] = id;
6551   egraph->stack.edata[k].ptr = expl;
6552 }
6553 
6554 
6555 
6556 /************************
6557  *  THEORY EXPLANATION  *
6558  ***********************/
6559 
6560 /*
6561  * Expand a theory implication:
6562  * - a theory solver called propagate_literal(core, l, expl)
6563  * - the core needs to convert expl to a conjunction of literals
6564  */
egraph_expand_explanation(egraph_t * egraph,literal_t l,void * expl,ivector_t * v)6565 void egraph_expand_explanation(egraph_t *egraph, literal_t l, void *expl, ivector_t *v) {
6566   void *atom;
6567   atom_t *a;
6568   occ_t u;
6569   int32_t id;
6570 
6571   assert(v->size == 0);
6572 
6573   atom = get_bvar_atom(egraph->core, var_of(l));
6574   switch (atom_tag(atom)) {
6575   case EGRAPH_ATM_TAG:
6576     a = (atom_t *) atom;
6577     assert(a->boolvar == var_of(l));
6578     assert(literal_is_assigned(egraph->core, l) &&
6579            bvar_value(egraph->core, var_of(l)) == egraph_term_truth_value(egraph, a->eterm));
6580     id = i32_of_expl(expl);    // id := edge that triggered the propagation
6581     u = mk_occ(a->eterm, sign_of(l));
6582 #if 0
6583     printf("---> EGRAPH: expand explanation for ");
6584     print_literal(stdout, l);
6585     printf(" (trigger edge = %"PRId32")\n", id);
6586 #endif
6587     /*
6588      * Build the explanation for u == true
6589      */
6590     egraph_explain_equality(egraph, u, true_occ, id, v);
6591     break;
6592 
6593   case ARITH_ATM_TAG:
6594     egraph->arith_smt->expand_explanation(egraph->th[ETYPE_INT], l, expl, v);
6595     break;
6596 
6597   case BV_ATM_TAG:
6598     egraph->bv_smt->expand_explanation(egraph->th[ETYPE_BV], l, expl, v);
6599     break;
6600   }
6601 }
6602 
6603 
6604 
6605 
6606 /*************************
6607  *  SPLITTING HEURISTIC  *
6608  ************************/
6609 
6610 /*
6611  * For an equality atom c = (eq t1 t2) and l attached to that atom
6612  * select whether to branch on l or (not l)
6613  * - if t1 and t2 are attached to theory variables, the decision is
6614  *   made by the satellite solver
6615  * - otherwise, return l
6616  */
egraph_select_eq_polarity(egraph_t * egraph,composite_t * c,literal_t l)6617 static literal_t egraph_select_eq_polarity(egraph_t *egraph, composite_t *c, literal_t l) {
6618   occ_t t1, t2;
6619   class_t c1, c2;
6620   thvar_t v1, v2;
6621   etype_t i;
6622 
6623   assert(composite_kind(c) == COMPOSITE_EQ);
6624 
6625   t1 = c->child[0];
6626   t2 = c->child[1];
6627   i = egraph_type(egraph, t1);
6628   if (i < NUM_SATELLITES) {
6629     c1 = egraph_class(egraph, t1);
6630     v1 = egraph->classes.thvar[c1];
6631     c2 = egraph_class(egraph, t2);
6632     v2 = egraph->classes.thvar[c2];
6633     if (v1 != null_thvar && v2 != null_thvar) {
6634       assert(egraph->eg[i] != NULL);
6635       return egraph->eg[i]->select_eq_polarity(egraph->th[i], v1, v2, pos_lit(var_of(l)));
6636     }
6637   }
6638 
6639   return l;
6640 }
6641 
6642 
6643 /*
6644  * Select whether to branch on l or (not l)
6645  * - atom = the atom attached to var_of(l)
6646  * - forward to the appropriate subsolver
6647  */
egraph_select_polarity(egraph_t * egraph,void * atom,literal_t l)6648 static literal_t egraph_select_polarity(egraph_t *egraph, void *atom, literal_t l) {
6649   atom_t *a;
6650   composite_t *c;
6651 
6652   switch (atom_tag(atom)) {
6653   case ARITH_ATM_TAG:
6654     return egraph->arith_smt->select_polarity(egraph->th[ETYPE_INT], untag_atom(atom), l);
6655 
6656   case BV_ATM_TAG:
6657     return egraph->bv_smt->select_polarity(egraph->th[ETYPE_BV], untag_atom(atom), l);
6658 
6659   case EGRAPH_ATM_TAG:
6660   default:
6661     // FOR EQUALITY ATOMS: defer to the satellite solver if any
6662     a = (atom_t *) untag_atom(atom);
6663     assert(a->boolvar == var_of(l));
6664     c = egraph_term_body(egraph, a->eterm);
6665     if (composite_body(c) && composite_kind(c) == COMPOSITE_EQ) {
6666       l = egraph_select_eq_polarity(egraph, c, l);
6667     }
6668     return l;
6669   }
6670 }
6671 
6672 
6673 
6674 
6675 
6676 
6677 
6678 /***********************
6679  *  CONTROL INTERFACE  *
6680  **********************/
6681 
6682 static th_ctrl_interface_t egraph_control = {
6683   (start_intern_fun_t) egraph_start_internalization,
6684   (start_fun_t) egraph_start_search,
6685   (propagate_fun_t) egraph_propagate,
6686   (final_check_fun_t) egraph_final_check,
6687   (increase_level_fun_t) egraph_increase_decision_level,
6688   (backtrack_fun_t) egraph_backtrack,
6689   (push_fun_t) egraph_push,
6690   (pop_fun_t) egraph_pop,
6691   (reset_fun_t) egraph_reset,
6692   (clear_fun_t) egraph_clear,
6693 };
6694 
6695 
6696 
6697 /*******************
6698  *  SMT INTERFACE  *
6699  ******************/
6700 
6701 static th_smt_interface_t egraph_smt = {
6702   (assert_fun_t) egraph_assert_atom,
6703   (expand_expl_fun_t) egraph_expand_explanation,
6704   (select_pol_fun_t) egraph_select_polarity,
6705   NULL,
6706   NULL,
6707 };
6708 
6709 
6710 
6711 
6712 /*************************
6713  *  EGRAPH CONSTRUCTION  *
6714  ************************/
6715 
6716 /*
6717  * Initialize all internal structures
6718  * - ttbl = attached type table
6719  * - use default initial sizes
6720  * - subsolver descriptors are all NULL and core is also NULL
6721  * - set all options and parameters to their default values
6722  */
init_egraph(egraph_t * egraph,type_table_t * ttbl)6723 void init_egraph(egraph_t *egraph, type_table_t *ttbl) {
6724   uint32_t i;
6725 
6726   egraph->core = NULL;
6727   egraph->types = ttbl;
6728 
6729   egraph->base_level = 0;
6730   egraph->decision_level = 0;
6731   egraph->presearch = false;
6732   egraph->ndistincts = 0;
6733   egraph->natoms = 0;
6734   egraph->is_high_order = false;
6735 
6736   init_egraph_stats(&egraph->stats);
6737 
6738   egraph->options = EGRAPH_DEFAULT_OPTIONS;
6739   egraph->max_ackermann = DEFAULT_MAX_ACKERMANN;
6740   egraph->max_boolackermann = DEFAULT_MAX_BOOLACKERMANN;
6741   egraph->aux_eq_quota = DEFAULT_AUX_EQ_QUOTA;
6742   egraph->ackermann_threshold = DEFAULT_ACKERMANN_THRESHOLD;
6743   egraph->boolack_threshold = DEFAULT_BOOLACK_THRESHOLD;
6744   egraph->max_interface_eqs = DEFAULT_MAX_INTERFACE_EQS;
6745   egraph->ack_left = null_occurrence;
6746   egraph->ack_right = null_occurrence;
6747 
6748   init_class_table(&egraph->classes, DEFAULT_CLASS_TABLE_SIZE);
6749   init_eterm_table(&egraph->terms, DEFAULT_ETERM_TABLE_SIZE);
6750   init_egraph_stack(&egraph->stack, DEFAULT_EGRAPH_STACK_SIZE, DEFAULT_EGRAPH_NLEVELS);
6751   init_undo_stack(&egraph->undo, DEFAULT_EGRAPH_STACK_SIZE, DEFAULT_EGRAPH_NLEVELS);
6752   init_distinct_table(&egraph->dtable);
6753   init_congruence_table(&egraph->ctable, 0);
6754   init_ltag_table(&egraph->tag_table);
6755 
6756   egraph->update_graph = NULL;
6757 
6758   init_egraph_trail(&egraph->trail_stack);
6759 
6760 
6761   // auxiliary buffers and data structures
6762   egraph->const_htbl = NULL;
6763   init_int_htbl(&egraph->htbl, 0);
6764   init_objstore(&egraph->atom_store, sizeof(atom_t), ATOM_BANK_SIZE);
6765   init_cache(&egraph->cache);
6766 
6767   egraph->imap = NULL;
6768   init_sign_buffer(&egraph->sgn);
6769   init_arena(&egraph->arena);
6770   init_ivector(&egraph->expl_queue, DEFAULT_EXPL_VECTOR_SIZE);
6771   init_ivector(&egraph->expl_vector, DEFAULT_EXPL_VECTOR_SIZE);
6772   init_pvector(&egraph->cmp_vector, DEFAULT_CMP_VECTOR_SIZE);
6773   init_ivector(&egraph->aux_buffer, 0);
6774   init_istack(&egraph->istack);
6775 
6776   egraph->short_cuts = true;
6777   egraph->top_id = 0;
6778 
6779   init_ivector(&egraph->interface_eqs, 40);
6780   egraph->reconcile_top = 0;
6781   egraph->reconcile_neqs = 0;
6782   egraph->reconcile_mode = false;
6783 
6784   init_pvector(&egraph->reanalyze_vector, 0);
6785   init_th_explanation(&egraph->th_expl);
6786   egraph->app_partition = NULL;
6787 
6788   // satellite solvers and descriptors
6789   for (i=0; i<NUM_SATELLITES; i++) {
6790     egraph->th[i] = NULL;
6791     egraph->ctrl[i] = NULL;
6792     egraph->eg[i] = NULL;
6793   }
6794   egraph->arith_smt = NULL;
6795   egraph->bv_smt = NULL;
6796   egraph->arith_eg = NULL;
6797   egraph->bv_eg = NULL;
6798   egraph->fun_eg = NULL;
6799 
6800   // model-construction object
6801   init_egraph_model(&egraph->mdl);
6802 }
6803 
6804 
6805 
6806 
6807 /*
6808  * Attach an arithmetic solver: it's used for both INT and REAL
6809  * - the control interface is attached only to type REAL
6810  *   so that push/pop/reset/start_search are not called twice
6811  */
egraph_attach_arithsolver(egraph_t * egraph,void * solver,th_ctrl_interface_t * ctrl,th_smt_interface_t * smt,th_egraph_interface_t * eg,arith_egraph_interface_t * arith_eg)6812 void egraph_attach_arithsolver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
6813                                th_smt_interface_t *smt, th_egraph_interface_t *eg,
6814                                arith_egraph_interface_t *arith_eg) {
6815 
6816   assert(egraph->core == NULL && egraph->arith_smt == NULL);
6817 
6818   egraph->th[ETYPE_INT] = solver;
6819   egraph->th[ETYPE_REAL] = solver;
6820   egraph->ctrl[ETYPE_INT] = NULL;
6821   egraph->ctrl[ETYPE_REAL] = ctrl;
6822   egraph->eg[ETYPE_INT] = eg;
6823   egraph->eg[ETYPE_REAL] = eg;
6824   egraph->arith_smt = smt;
6825   egraph->arith_eg = arith_eg;
6826 }
6827 
6828 
6829 /*
6830  * Attach a bitvector solver
6831  */
egraph_attach_bvsolver(egraph_t * egraph,void * solver,th_ctrl_interface_t * ctrl,th_smt_interface_t * smt,th_egraph_interface_t * eg,bv_egraph_interface_t * bv_eg)6832 void egraph_attach_bvsolver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
6833                             th_smt_interface_t *smt, th_egraph_interface_t *eg,
6834                             bv_egraph_interface_t *bv_eg) {
6835 
6836   assert(egraph->core == NULL && egraph->bv_smt == NULL);
6837 
6838   egraph->th[ETYPE_BV] = solver;
6839   egraph->ctrl[ETYPE_BV] = ctrl;
6840   egraph->eg[ETYPE_BV] = eg;
6841   egraph->bv_smt = smt;
6842   egraph->bv_eg = bv_eg;
6843 }
6844 
6845 
6846 /*
6847  * Attach a function subsolver
6848  * - solver = pointer to the subsolver object
6849  * - ctrl, eg, fun_eg  = interface descriptors
6850  */
egraph_attach_funsolver(egraph_t * egraph,void * solver,th_ctrl_interface_t * ctrl,th_egraph_interface_t * eg,fun_egraph_interface_t * fun_eg)6851 void egraph_attach_funsolver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
6852                              th_egraph_interface_t *eg, fun_egraph_interface_t *fun_eg) {
6853   etype_t id;
6854 
6855   assert(egraph->core == NULL && egraph->ctrl[ETYPE_FUNCTION] == NULL);
6856 
6857   id = ETYPE_FUNCTION;
6858   egraph->th[id] = solver;
6859   egraph->ctrl[id] = ctrl;
6860   egraph->eg[id] = eg;
6861   egraph->fun_eg = fun_eg;
6862 }
6863 
6864 
6865 /*
6866  * Get the egraph control and smt interfaces:
6867  */
egraph_ctrl_interface(egraph_t * egraph)6868 th_ctrl_interface_t *egraph_ctrl_interface(egraph_t *egraph) {
6869   return &egraph_control;
6870 }
6871 
egraph_smt_interface(egraph_t * egraph)6872 th_smt_interface_t *egraph_smt_interface(egraph_t *egraph) {
6873   return &egraph_smt;
6874 }
6875 
6876 
6877 /*
6878  * Attach the core to the egraph
6879  * - the core must be initialized with the egraph_control and egraph_smt_interface
6880  */
egraph_attach_core(egraph_t * egraph,smt_core_t * core)6881 void egraph_attach_core(egraph_t *egraph, smt_core_t *core) {
6882   assert(core != NULL && core->th_solver == egraph);
6883 
6884   egraph->core = core;
6885   egraph_init_constant(egraph);
6886 }
6887 
6888 
6889 /*
6890  * Delete everything
6891  */
delete_egraph(egraph_t * egraph)6892 void delete_egraph(egraph_t *egraph) {
6893   delete_egraph_model(&egraph->mdl);
6894   if (egraph->app_partition != NULL) {
6895     delete_ptr_partition(egraph->app_partition);
6896     safe_free(egraph->app_partition);
6897     egraph->app_partition = NULL;
6898   }
6899   delete_th_explanation(&egraph->th_expl);
6900   delete_pvector(&egraph->reanalyze_vector);
6901   delete_ivector(&egraph->interface_eqs);
6902   delete_istack(&egraph->istack);
6903   delete_ivector(&egraph->aux_buffer);
6904   delete_pvector(&egraph->cmp_vector);
6905   delete_ivector(&egraph->expl_vector);
6906   delete_ivector(&egraph->expl_queue);
6907   delete_arena(&egraph->arena);
6908   delete_sign_buffer(&egraph->sgn);
6909   if (egraph->imap != NULL) {
6910     delete_int_hmap(egraph->imap);
6911     safe_free(egraph->imap);
6912     egraph->imap = NULL;
6913   }
6914   delete_cache(&egraph->cache);
6915   delete_objstore(&egraph->atom_store);
6916   delete_int_htbl(&egraph->htbl);
6917   egraph_free_const_htbl(egraph);
6918   delete_egraph_trail(&egraph->trail_stack);
6919   delete_ltag_table(&egraph->tag_table);
6920   delete_congruence_table(&egraph->ctable);
6921   delete_undo_stack(&egraph->undo);
6922   delete_egraph_stack(&egraph->stack);
6923   delete_eterm_table(&egraph->terms);
6924   delete_class_table(&egraph->classes);
6925 }
6926 
6927 
6928 
6929 
6930 /*************************************
6931  *  SUPPORT FOR ARRAY-THEORY SOLVER  *
6932  ************************************/
6933 
6934 // TODO: MIGRATE ALL THIS TO THE UPDATE-GRAPH MODULE
6935 
6936 /*
6937  * Get the lambda tag for function type tau
6938  * - tau must be a function type
6939  */
egraph_get_lambda_tag(egraph_t * egraph,type_t tau)6940 int32_t egraph_get_lambda_tag(egraph_t *egraph, type_t tau) {
6941   return lambda_tag_for_type(&egraph->tag_table, egraph->types, tau);
6942 }
6943 
6944 
6945 /*
6946  * Collect all composite terms of the form (apply g ....)
6947  * where g is in the same class as f
6948  * - only the congruence roots are collected
6949  * - they are added to the pointer vector *v
6950  */
egraph_collect_applications(egraph_t * egraph,eterm_t f,pvector_t * v)6951 void egraph_collect_applications(egraph_t *egraph, eterm_t f, pvector_t *v) {
6952   use_vector_t *u;
6953   composite_t *p;
6954   class_t c;
6955   occ_t g;
6956   uint32_t i, n;
6957 
6958   c = egraph_term_class(egraph, f);
6959   u = egraph_class_parents(egraph, c);
6960   n = u->last;
6961   for (i=0; i<n; i++) {
6962     p = u->data[i];
6963     if (valid_entry(p) && composite_kind(p) == COMPOSITE_APPLY) {
6964       g = composite_child(p, 0); // function term of p
6965       if (egraph_class(egraph, g) == c) {
6966         pvector_push(v, p);
6967       }
6968     }
6969   }
6970 }
6971 
6972 
6973 /*
6974  * Return a term congruent to (apply g i_1 ... i_n) or NULL_COMPOSITE if there isn't one
6975  * - c = composite of the form (apply f i_1 ... i_n)
6976  */
egraph_find_modified_application(egraph_t * egraph,eterm_t g,composite_t * c)6977 composite_t *egraph_find_modified_application(egraph_t *egraph, eterm_t g, composite_t *c) {
6978   signature_t *sgn;
6979   elabel_t *label;
6980 
6981   assert(composite_kind(c) == COMPOSITE_APPLY);
6982 
6983   label = egraph->terms.label;
6984   sgn = &egraph->sgn;
6985   signature_modified_apply(c, g, label, sgn);
6986   return congruence_table_find(&egraph->ctable, sgn, label);
6987 }
6988 
6989 
6990 #if 0
6991 
6992 // NOT USED
6993 /*
6994  * Return a randomly chosen class label of type tau
6995  * - if there's no term of type tau, return null_label
6996  */
6997 elabel_t egraph_get_label_for_type(egraph_t *egraph, type_t tau) {
6998   uint32_t n, k;
6999   eterm_t t, u;
7000 
7001 
7002   if (is_boolean_type(tau)) {
7003     // select true or false randomly
7004     k = random_uint32();
7005     if (k & 0x400) {
7006       return true_label;
7007     } else {
7008       return false_label;
7009     }
7010 
7011   } else {
7012 
7013     n = egraph_num_terms(egraph);
7014     u = null_eterm;
7015     k = 0;
7016     for (t=0; t<n; t++) {
7017       if (egraph_term_real_type(egraph, t) == tau) {
7018         k ++;
7019         if (random_uint(k) == 0) {
7020           u = t;
7021         }
7022       }
7023     }
7024     if (u == null_eterm) {
7025       return null_label;
7026     } else {
7027       return egraph_term_label(egraph, u);
7028     }
7029   }
7030 }
7031 
7032 #endif
7033 
7034 
7035 /*
7036  * Fill in array a with at most n distinct class labels of type tau.
7037  * If there are fewer than n classes of type tau, then the array is
7038  * partially filled (in a[0 ... k-1])
7039  * - return the number of labels k actually stored in a (k <= n)
7040  */
egraph_get_labels_for_type(egraph_t * egraph,type_t tau,elabel_t * a,uint32_t n)7041 uint32_t egraph_get_labels_for_type(egraph_t *egraph, type_t tau, elabel_t *a, uint32_t n) {
7042   uint32_t k, p;
7043   class_t c;
7044   eterm_t t;
7045 
7046   assert(n > 0);
7047 
7048   if (is_boolean_type(tau)) {
7049     if (n == 1) {
7050       a[0] = true_label;
7051       return 1;
7052     } else {
7053       a[0] = true_label;
7054       a[1] = false_label;
7055       return 2;
7056     }
7057 
7058   } else {
7059 
7060     p = egraph_num_classes(egraph);
7061     k = 0;
7062     for (c=0; c<p; c++) {
7063       if (egraph_class_is_root_class(egraph, c)) {
7064         t = term_of_occ(egraph_class_root(egraph, c));
7065         if (egraph_term_real_type(egraph, t) == tau) {
7066           assert(k < n);
7067           a[k] = pos_label(c);
7068           assert(a[k] == egraph_term_label(egraph, t));
7069           k ++;
7070           if (k == n) break;
7071         }
7072       }
7073     }
7074 
7075     return k;
7076   }
7077 }
7078 
7079 
7080 #if 0
7081 
7082 // NOT USED
7083 /*
7084  * Number of classes of type tau in the egraph
7085  */
7086 uint32_t egraph_num_classes_of_type(egraph_t *egraph, type_t tau) {
7087   int32_t c, n;
7088   eterm_t t;
7089   uint32_t k;
7090 
7091   k = 0;
7092   n = egraph_num_classes(egraph);
7093   for (c=0; c<n; c++) {
7094     if (egraph_class_is_root_class(egraph, c)) {
7095       t = term_of_occ(egraph_class_root(egraph, c));
7096       if (egraph_term_real_type(egraph, t) == tau) {
7097         k ++;
7098       }
7099     }
7100   }
7101 
7102   // for booleans, we double k because of polarity
7103   if (is_boolean_type(tau)) {
7104     k *= 2;
7105   }
7106 
7107   return k;
7108 }
7109 
7110 #endif
7111 
7112 
7113 /*
7114  * Hash and match functions for partition table
7115  */
hash_arg(egraph_t * egraph,composite_t * c)7116 static uint32_t hash_arg(egraph_t *egraph, composite_t *c) {
7117   return hash_arg_signature(c, egraph->terms.label);
7118 }
7119 
match_arg(egraph_t * egraph,composite_t * c,composite_t * d)7120 static bool match_arg(egraph_t *egraph, composite_t *c, composite_t *d) {
7121   return same_arg_signature(c, d, egraph->terms.label);
7122 }
7123 
7124 
7125 
7126 /*
7127  * Return the partition structure.
7128  * Allocate and initialize it if needed.
7129  */
egraph_get_app_partition(egraph_t * egraph)7130 static ppart_t *egraph_get_app_partition(egraph_t *egraph) {
7131   ppart_t *pp;
7132 
7133   pp = egraph->app_partition;
7134   if (pp == NULL) {
7135     pp = (ppart_t *) safe_malloc(sizeof(ppart_t));
7136     init_ptr_partition(pp, 0, egraph, (ppart_hash_fun_t) hash_arg, (ppart_match_fun_t) match_arg);
7137     egraph->app_partition = pp;
7138   }
7139   // the pp structure should be empty here
7140   assert(pp->nelems == 0 && pp->nclasses == 0);
7141 
7142   return pp;
7143 }
7144 
7145 
7146 
7147 /*
7148  * Build a partition of the (apply ...) terms in the egraph
7149  * based on argument matches.
7150  * - scan all composite terms that are (apply ...) and congruence roots
7151  * - add them one by one to the pp structure
7152  * - two terms (apply f t_1 ... t_n) and (apply g u_1 ... u_m)
7153  *   are in the same partition if their arguments are equal in the egraph:
7154  *   (i.e., n = m and t_1 == u_1 and ... and t_n == u_m)
7155  * Result:
7156  * - all non-singleton classes are stored in pp->classes
7157  *   (cf. ptr_partitions.h and ptr_partitions.c)
7158  */
egraph_build_arg_partition(egraph_t * egraph)7159 void egraph_build_arg_partition(egraph_t *egraph) {
7160   //  uint32_t i, n;
7161   uint32_t n;
7162   composite_t *cmp;
7163   ppart_t *pp;
7164 
7165   pp = egraph_get_app_partition(egraph);
7166   n = egraph_num_terms(egraph);
7167   //  for (i=0; i<n; i++) {
7168   //    cmp = egraph_term_body(egraph, i);
7169   // test: do this in reverse order
7170   while (n > 0) {
7171     n --;
7172     cmp = egraph_term_body(egraph, n);
7173     if (composite_body(cmp) &&
7174         composite_kind(cmp) == COMPOSITE_APPLY &&
7175         congruence_table_is_root(&egraph->ctable, cmp, egraph->terms.label)) {
7176       ptr_partition_add(pp, cmp);
7177     }
7178   }
7179 }
7180 
7181 
7182 /************************
7183  *  MODEL CONSTRUCTION  *
7184  ***********************/
7185 
7186 /*
7187  * Return the value of term occurrence t in the egraph model
7188  * - the value of all root classes should be available in array value
7189  */
egraph_get_value(egraph_t * egraph,value_table_t * vtbl,occ_t t)7190 value_t egraph_get_value(egraph_t *egraph, value_table_t *vtbl, occ_t t) {
7191   elabel_t l;
7192   value_t v;
7193 
7194   assert(egraph->mdl.value != NULL && egraph_occ_is_valid(egraph, t));
7195 
7196   l = egraph_label(egraph, t);
7197   if (is_pos_label(l)) {
7198     v = egraph->mdl.value[class_of(l)];
7199   } else if (l == false_label) {
7200     v = vtbl_mk_false(vtbl);
7201   } else {
7202     // this should not happen, but just to be safe we return unknown
7203     v = vtbl_mk_unknown(vtbl);
7204   }
7205 
7206   return v;
7207 }
7208 
7209 
7210 /*
7211  * Get the type of class c: check the root term's type
7212  * - if that type is TUPLE/FUNCTION/REAL, the root type may not be
7213  *   precise enough, so we check the other elements in the class
7214  * - otherwise, return the root type
7215  */
egraph_real_type_of_class(egraph_t * egraph,class_t c)7216 static type_t egraph_real_type_of_class(egraph_t *egraph, class_t c) {
7217   type_table_t *types;
7218   type_t tau, sigma;
7219   occ_t t, u;
7220 
7221   t = egraph_class_root(egraph, c);
7222   tau = egraph_term_real_type(egraph, term_of_occ(t));
7223   assert(tau != NULL_TYPE);
7224 
7225   types = egraph->types;
7226   switch (type_kind(types, tau)) {
7227   case REAL_TYPE:
7228     u = t;
7229     do {
7230       // check whether there's an integer object in the class
7231       u = egraph_next(egraph, u);
7232       assert(term_of_occ(t) != term_of_occ(u) || t == u);
7233       tau = egraph_term_real_type(egraph, term_of_occ(u));
7234       assert(is_arithmetic_type(tau));
7235     } while (t != u && is_real_type(tau));
7236     break;
7237 
7238   case TUPLE_TYPE:
7239   case FUNCTION_TYPE:
7240     u = egraph_next(egraph, t);
7241     while (u != t) {
7242       // refine the type tau
7243       // TODO: we could optimize this to avoid creating the
7244       // intermediate subtypes??
7245       assert(term_of_occ(t) != term_of_occ(u));
7246       sigma = egraph_term_real_type(egraph, term_of_occ(u));
7247       tau = inf_type(types, tau, sigma);
7248       assert(tau != NULL_TYPE);
7249       u = egraph_next(egraph, u);
7250     }
7251     break;
7252 
7253   default:
7254     break;
7255   }
7256 
7257   return tau;
7258 }
7259 
7260 
7261 /*
7262  * Convert an abstract value (particle x) to a concrete value
7263  * - the particle is from egraph->mdl.pstore
7264  * - x must be either a labeled particle of a fresh particle (not a tuple)
7265  */
egraph_concretize_value(egraph_t * egraph,value_table_t * vtbl,particle_t x)7266 static value_t egraph_concretize_value(egraph_t *egraph, value_table_t *vtbl, particle_t x) {
7267   pstore_t *pstore;
7268   value_t v;
7269   elabel_t l;
7270 
7271   pstore = egraph->mdl.pstore;
7272   v = particle_concrete_value(pstore, x);
7273   if (v == null_value) {
7274     switch (particle_kind(pstore, x)) {
7275     case LABEL_PARTICLE:
7276       l = particle_label(pstore, x);
7277       if (is_pos_label(l)) {
7278         v = egraph->mdl.value[class_of(l)];
7279         assert(! object_is_unknown(vtbl, v));
7280       } else if (l == false_label) {
7281         v  = vtbl_mk_false(vtbl);
7282       } else {
7283         // should not happen
7284         assert(false);
7285         v = vtbl_mk_unknown(vtbl);
7286       }
7287       break;
7288 
7289     case FRESH_PARTICLE:
7290       v = make_fresh_value(egraph->mdl.fval_maker, fresh_particle_type(pstore, x));
7291       break;
7292 
7293     default:
7294       assert(false);
7295       abort();
7296     }
7297     pstore_make_concrete(pstore, x, v);
7298   }
7299 
7300   return v;
7301 }
7302 
7303 
7304 /*
7305  * Concretize a tuple particle x
7306  * - the result is stored as n concrete values in v[0 ... n-1]
7307  * - the tuple must have n components
7308  */
egraph_concretize_tuple(egraph_t * egraph,value_table_t * vtbl,particle_t x,uint32_t n,value_t * v)7309 static void egraph_concretize_tuple(egraph_t *egraph, value_table_t *vtbl, particle_t x, uint32_t n, value_t *v) {
7310   particle_tuple_t *tuple;
7311   uint32_t i;
7312 
7313   tuple = tuple_particle_desc(egraph->mdl.pstore, x);
7314   assert(tuple->nelems == n);
7315   for (i=0; i<n; i++) {
7316     v[i] = egraph_concretize_value(egraph, vtbl, tuple->elem[i]);
7317   }
7318 }
7319 
7320 
7321 /*
7322  * Conversion of a map of abstract values to a function object
7323  * - map = the function map (abstract)
7324  * - tau = function type
7325  *
7326  * For every element [idx -> val] of map, we add the mapping (f i) = v to f.
7327  * where i = concretization of idx and v = concretization of val
7328  */
egraph_concretize_map(egraph_t * egraph,value_table_t * vtbl,map_t * map,type_t tau)7329 static value_t egraph_concretize_map(egraph_t *egraph, value_table_t *vtbl, map_t *map, type_t tau) {
7330   value_t *aux;
7331   value_t *all_maps;
7332   value_t buffer[1];
7333   value_t v;
7334   uint32_t i, n, m;
7335 
7336   n = function_type_arity(egraph->types, tau);
7337   m = map->nelems;
7338 
7339   all_maps = alloc_istack_array(&egraph->istack, m);
7340 
7341   if (n == 1) {
7342     for (i=0; i<m; i++) {
7343       buffer[0] = egraph_concretize_value(egraph, vtbl, map->data[i].index);
7344       v = egraph_concretize_value(egraph, vtbl, map->data[i].value);
7345       all_maps[i] = vtbl_mk_map(vtbl, 1, buffer, v);
7346     }
7347   } else {
7348     aux = alloc_istack_array(&egraph->istack, n);
7349 
7350     for (i=0; i<m; i++) {
7351       egraph_concretize_tuple(egraph, vtbl, map->data[i].index, n, aux);
7352       v = egraph_concretize_value(egraph, vtbl, map->data[i].value);
7353       all_maps[i] = vtbl_mk_map(vtbl, n, aux, v);
7354     }
7355 
7356     free_istack_array(&egraph->istack, aux);
7357   }
7358 
7359   // get the default value
7360   if (map->def != null_particle) {
7361     v = egraph_concretize_value(egraph, vtbl, map->def);
7362   } else {
7363     v = vtbl_mk_unknown(vtbl);
7364   }
7365 
7366   // build the function
7367   v = vtbl_mk_function(vtbl, tau, m, all_maps, v);
7368 
7369   free_istack_array(&egraph->istack, all_maps);
7370 
7371   return v;
7372 }
7373 
7374 
7375 /*
7376  * Value for an arithmetic class c.
7377  * c must have etype INT or REAL
7378  */
egraph_value_of_arith_class(egraph_t * egraph,value_table_t * vtbl,class_t c)7379 static value_t egraph_value_of_arith_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
7380   rational_t *aux;
7381   thvar_t x;
7382   value_t v;
7383 
7384   assert(egraph_class_type(egraph, c) == ETYPE_INT || egraph_class_type(egraph, c) == ETYPE_REAL);
7385 
7386   x = egraph_class_thvar(egraph, c);
7387   if (x == null_thvar) {
7388     // there's no arithmetic solver
7389     assert(egraph->arith_smt == NULL);
7390     v = make_fresh_integer(egraph->mdl.fval_maker);
7391   } else {
7392     // there must be an arithmetic solver and it must have assigned a value to x
7393     aux = &egraph->mdl.arith_buffer;
7394     if (egraph->arith_eg->value_in_model(egraph->th[ETYPE_INT], x, aux)) {
7395       v = vtbl_mk_rational(vtbl, aux);
7396     } else {
7397       v = vtbl_mk_unknown(vtbl);
7398     }
7399   }
7400   return v;
7401 }
7402 
7403 
7404 /*
7405  * Value for a bitvector class c.
7406  * c must have etype BV
7407  */
egraph_value_of_bv_class(egraph_t * egraph,value_table_t * vtbl,class_t c)7408 static value_t egraph_value_of_bv_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
7409   bvconstant_t *bv;
7410   thvar_t x;
7411   value_t v;
7412   uint32_t n;
7413   type_t tau;
7414 
7415   assert(egraph_class_type(egraph, c) == ETYPE_BV);
7416   x = egraph_class_thvar(egraph, c);
7417   if (x == null_thvar) {
7418     // no bitvector solver
7419     assert(egraph->bv_smt == NULL);
7420     tau = egraph_real_type_of_class(egraph, c);
7421     n = bv_type_size(egraph->types, tau);
7422     v = make_fresh_bv(egraph->mdl.fval_maker, n);
7423   } else {
7424     // there must be a bitvector solver and it must have assigned a value to x
7425     bv = &egraph->mdl.bv_buffer;
7426     if (egraph->bv_eg->value_in_model(egraph->th[ETYPE_BV], x, bv)) {
7427       v = vtbl_mk_bv_from_constant(vtbl, bv);
7428     } else {
7429       v = vtbl_mk_unknown(vtbl);
7430     }
7431   }
7432 
7433   return v;
7434 }
7435 
7436 /*
7437  * Value for a tuple class c
7438  * c must have etype TUPLE
7439  */
egraph_value_of_tuple_class(egraph_t * egraph,value_table_t * vtbl,class_t c)7440 static value_t egraph_value_of_tuple_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
7441   composite_t *cmp;
7442   value_t *aux;
7443   value_t v;
7444   eterm_t x;
7445   uint32_t i, n;
7446 
7447   assert(egraph_class_type(egraph, c) == ETYPE_TUPLE);
7448   x = egraph_class_thvar(egraph, c);
7449   if (x != null_eterm) {
7450     /*
7451      * x is a (tuple ...) composite in the class
7452      */
7453     cmp = egraph_term_body(egraph, x);
7454     assert(cmp != NULL && composite_body(cmp) && composite_kind(cmp) == COMPOSITE_TUPLE);
7455 
7456     n = composite_arity(cmp);
7457     aux = alloc_istack_array(&egraph->istack, n);
7458 
7459     // get a value for all the children classes
7460     // they should all have a non-null value
7461     for (i=0; i<n; i++) {
7462       aux[i] = egraph_get_value(egraph, vtbl, composite_child(cmp, i));
7463     }
7464 
7465     v = vtbl_mk_tuple(vtbl, n, aux);
7466 
7467     free_istack_array(&egraph->istack, aux);
7468 
7469   } else {
7470     // This should never happen
7471     assert(false);
7472     v = vtbl_mk_unknown(vtbl);
7473   }
7474 
7475   return v;
7476 }
7477 
7478 
7479 /*
7480  * Convert composite p to a mapping object
7481  * - p must be (apply f a[0] .. a[n-1])
7482  * - we construct the mapping object (v[0] ... v[n-1] |-> r)
7483  *   where v[i] = value of a[i]
7484  *            r = value of class of p
7485  */
egraph_composite_value(egraph_t * egraph,value_table_t * vtbl,composite_t * p)7486 static value_t egraph_composite_value(egraph_t *egraph, value_table_t *vtbl, composite_t *p) {
7487   value_t *aux;
7488   value_t v;
7489   uint32_t i, n;
7490 
7491   assert(composite_kind(p) == COMPOSITE_APPLY);
7492   n = composite_arity(p);
7493   assert(n >= 2);
7494   n --;
7495 
7496   aux = alloc_istack_array(&egraph->istack, n);
7497 
7498   // values of a[0] ... a[n-1]
7499   // they should all be defined
7500   for (i=0; i<n; i++) {
7501     aux[i] = egraph_get_value(egraph, vtbl, composite_child(p, i+1));
7502   }
7503 
7504   // value of f
7505   v = egraph_get_value(egraph, vtbl, pos_occ(p->id));
7506 
7507   // build the mapping object [aux[0] ... aux[n-1] -> v]
7508   v = vtbl_mk_map(vtbl, n, aux, v);
7509 
7510   free_istack_array(&egraph->istack, aux);
7511 
7512   return v;
7513 }
7514 
7515 
7516 /*
7517  * Build a mapping from the composite terms in c's parent vector
7518  * - tau = type of class c
7519  */
egraph_make_fun_value(egraph_t * egraph,value_table_t * vtbl,class_t c,type_t tau)7520 static value_t egraph_make_fun_value(egraph_t *egraph, value_table_t *vtbl, class_t c, type_t tau) {
7521   use_vector_t *u;
7522   composite_t *p;
7523   occ_t g;
7524   uint32_t i, n, j;
7525   value_t *all_maps;
7526   value_t v;
7527 
7528   u = egraph_class_parents(egraph, c);
7529   n = u->last;
7530 
7531   assert(n < VTBL_MAX_MAP_SIZE);
7532   all_maps = alloc_istack_array(&egraph->istack, n);
7533 
7534   j = 0;
7535   for (i=0; i<n; i++) {
7536     p = u->data[i];
7537     if (valid_entry(p) && composite_kind(p) == COMPOSITE_APPLY) {
7538       g = composite_child(p, 0); // function term of p
7539       if (egraph_class(egraph, g) == c) {
7540         all_maps[j] = egraph_composite_value(egraph, vtbl, p);
7541         j ++;
7542       }
7543     }
7544   }
7545 
7546   // function without a default value
7547   v = vtbl_mk_function(vtbl, tau, j, all_maps, vtbl_mk_unknown(vtbl));
7548 
7549   free_istack_array(&egraph->istack, all_maps);
7550 
7551   return v;
7552 }
7553 
7554 
7555 /*
7556  * Value for a array/function class c.
7557  * c must have etype FUNCTION
7558  */
egraph_value_of_fun_class(egraph_t * egraph,value_table_t * vtbl,class_t c)7559 static value_t egraph_value_of_fun_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
7560   map_t *map;
7561   thvar_t x;
7562   value_t v;
7563   type_t tau;
7564 
7565   assert(egraph_class_type(egraph, c) == ETYPE_FUNCTION);
7566   x = egraph_class_thvar(egraph, c);
7567   tau = egraph_real_type_of_class(egraph, c);
7568   if (x == null_thvar) {
7569     /*
7570      * no array/function solver: create a new function
7571      * using the composites terms in c's parent vector
7572      */
7573     v = egraph_make_fun_value(egraph, vtbl, c, tau);
7574   } else {
7575     /*
7576      * there is a function solver and it must have assigned a value to x
7577      */
7578     assert(egraph->fun_eg != NULL);
7579     map = egraph->fun_eg->value_in_model(egraph->th[ETYPE_FUNCTION], x);
7580     if (map != NULL) {
7581       v = egraph_concretize_map(egraph, vtbl, map, tau);
7582     } else {
7583       v = vtbl_mk_unknown(vtbl);
7584     }
7585   }
7586 
7587   return v;
7588 }
7589 
7590 
7591 /*
7592  * Value of an uninterpreted class c
7593  * c must have etype NONE
7594  */
egraph_value_of_uninterpreted_class(egraph_t * egraph,value_table_t * vtbl,class_t c)7595 static value_t egraph_value_of_uninterpreted_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
7596   occ_t root;
7597   eterm_t t;
7598   type_t tau;
7599   value_t v;
7600 
7601   /*
7602    * Search for a constant t in the class. If there's none
7603    * create an anonymous uninterpreted constant/
7604    */
7605   root = egraph_class_root(egraph, c);
7606   assert(is_pos_occ(root));
7607   tau = egraph_term_real_type(egraph, term_of_occ(root));
7608   assert(tau != NULL_TYPE);
7609 
7610   if ((egraph->classes.dmask[c] & 0x1) != 0) {
7611     // the class contains a constant
7612     t = term_of_occ(root);
7613     while (! constant_body(egraph_term_body(egraph, t))) {
7614       t = term_of_occ(egraph->terms.next[t]);
7615       assert(t != term_of_occ(root)); // make sure we don't loop forever
7616     }
7617 
7618     // v = constant of type tau and same id as t, no name
7619     v = vtbl_mk_const(vtbl, tau, constant_body_id(egraph_term_body(egraph, t)), NULL);
7620 
7621   } else {
7622     // fresh anonymous constant
7623     v = make_fresh_const(egraph->mdl.fval_maker, tau);
7624   }
7625 
7626   return v;
7627 }
7628 
7629 
7630 /*
7631  * Get the value of class c
7632  */
egraph_value_of_class(egraph_t * egraph,value_table_t * vtbl,class_t c)7633 static value_t egraph_value_of_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
7634   value_t v;
7635 
7636   switch (egraph_class_type(egraph, c)) {
7637   case ETYPE_INT:
7638   case ETYPE_REAL:
7639     v = egraph_value_of_arith_class(egraph, vtbl, c);
7640     break;
7641 
7642   case ETYPE_FUNCTION:
7643     v = egraph_value_of_fun_class(egraph, vtbl, c);
7644     break;
7645 
7646   case ETYPE_BV:
7647     v = egraph_value_of_bv_class(egraph, vtbl, c);
7648     break;
7649 
7650   case ETYPE_BOOL:
7651     /*
7652      * If all literals are assigned in the core, then all the boolean terms are in
7653      * the bool_constant_class. So the value[c] must be true.
7654      */
7655     assert(c == bool_constant_class &&
7656            bvar_value(egraph->core, egraph_class_thvar(egraph, c)) == VAL_TRUE);
7657     v = vtbl_mk_true(vtbl);
7658     break;
7659 
7660   case ETYPE_TUPLE:
7661     v = egraph_value_of_tuple_class(egraph, vtbl, c);
7662     break;
7663 
7664   case ETYPE_NONE:
7665     v = egraph_value_of_uninterpreted_class(egraph, vtbl, c);
7666     break;
7667 
7668   default:
7669     /*
7670      * Should not happen
7671      */
7672     assert(false);
7673     v = vtbl_mk_unknown(vtbl);
7674     break;
7675   }
7676 
7677   return v;
7678 }
7679 
7680 
7681 /*
7682  * Assign a value to all the root classes
7683  * - the root classes must be stored in egraph->mdl.root_classes
7684  */
egraph_model_for_root_classes(egraph_t * egraph,value_table_t * vtbl)7685 static void egraph_model_for_root_classes(egraph_t *egraph, value_table_t *vtbl) {
7686   ivector_t *v;
7687   uint32_t i, n;
7688   class_t c;
7689 
7690   v = &egraph->mdl.root_classes;
7691   n = v->size;
7692   for (i=0; i<n; i++) {
7693     c = v->data[i];
7694     assert(egraph->mdl.value[c] == null_value &&
7695            egraph_class_is_root_class(egraph, c));
7696     egraph->mdl.value[c] = egraph_value_of_class(egraph, vtbl, c);
7697   }
7698 }
7699 
7700 
7701 
7702 /*
7703  * Rank of a class c
7704  */
egraph_class_rank(egraph_t * egraph,class_t c)7705 static uint32_t egraph_class_rank(egraph_t *egraph, class_t c) {
7706   occ_t t;
7707   type_t tau;
7708 
7709   t = egraph_class_root(egraph, c);
7710   tau = egraph_term_real_type(egraph, term_of_occ(t));
7711   return type_depth(egraph->types, tau);
7712 }
7713 
7714 
7715 /*
7716  * Increment rank counter k
7717  * - ctr = vector of counters
7718  * - also initialize all counters of rank < k if needed
7719  */
egraph_increment_rank_counter(ivector_t * ctr,uint32_t k)7720 static void egraph_increment_rank_counter(ivector_t *ctr, uint32_t k) {
7721   uint32_t i;
7722 
7723   if (ctr->size <= k) {
7724     resize_ivector(ctr, k+1);
7725     assert(ctr->capacity > k);
7726     for (i=ctr->size; i<=k; i++) {
7727       ctr->data[i] = 0;
7728     }
7729     ctr->size = k+1;
7730   }
7731   ctr->data[k] ++;
7732 }
7733 
7734 
7735 /*
7736  * Collect all root classes
7737  * - store them in mdl->root_classes, sorted by increasing rank
7738  */
egraph_collect_root_classes(egraph_t * egraph)7739 static void egraph_collect_root_classes(egraph_t *egraph) {
7740   ivector_t *v;
7741   ivector_t *ctr;
7742   uint32_t i, j, n, k, s;
7743 
7744   ctr = &egraph->mdl.rank_ctr;
7745   ivector_reset(ctr);
7746 
7747   // first pass: count the number of root classes per rank
7748   n = egraph_num_classes(egraph);
7749   for (i=0; i<n; i++) {
7750     if (egraph_class_is_root_class(egraph, i)) {
7751       k = egraph_class_rank(egraph, i);
7752       egraph_increment_rank_counter(ctr, k);
7753     }
7754   }
7755 
7756   s = 0;
7757   n = ctr->size;
7758   for (i=0; i<n; i++) {
7759     k = ctr->data[i]; // number of classes of rank i
7760     ctr->data[i] = s; // number of classes of rank < I
7761     s += k;
7762   }
7763 
7764   /*
7765    * s = total number of root classes
7766    * store the classes in increasing
7767    * rank order in egraph->mdl.root_classes;
7768    */
7769   v = &egraph->mdl.root_classes;
7770   resize_ivector(v, s);
7771   v->size = s;
7772   n = egraph_num_classes(egraph);
7773   for (i=0; i<n; i++) {
7774     if (egraph_class_is_root_class(egraph, i)) {
7775       k = egraph_class_rank(egraph, i);
7776       assert(k < ctr->size);
7777       j = ctr->data[k];
7778       v->data[j] = i;
7779       ctr->data[k] = j+1;
7780     }
7781   }
7782 }
7783 
7784 
7785 /*
7786  * Build a model: the model maps egraph classes to objects built in vtbl
7787  */
egraph_build_model(egraph_t * egraph,value_table_t * vtbl)7788 void egraph_build_model(egraph_t *egraph, value_table_t *vtbl) {
7789   uint32_t i, n;
7790   pstore_t *pstore;
7791   fresh_val_maker_t *fval;
7792 
7793   /*
7794    * Allocate and initialize the value array
7795    */
7796   n = egraph->classes.nclasses;
7797   egraph->mdl.value = (value_t *) safe_malloc(n * sizeof(value_t));
7798   for (i=0; i<n; i++) {
7799     egraph->mdl.value[i] = null_value;
7800   }
7801 
7802   /*
7803    * Allocate and initialize the pstore then build the array model
7804    */
7805   if (egraph->fun_eg != NULL) {
7806     pstore = (pstore_t *) safe_malloc(sizeof(pstore_t));
7807     egraph->mdl.pstore = pstore;
7808     init_pstore(pstore, egraph->types);
7809     egraph->fun_eg->build_model(egraph->th[ETYPE_FUNCTION], pstore);
7810   }
7811 
7812   /*
7813    * Allocate the free_val_maker:
7814    * - it may be needed even if we don't have a function solver
7815    */
7816   fval = (fresh_val_maker_t *) safe_malloc(sizeof(fresh_val_maker_t));
7817   init_fresh_val_maker(fval, vtbl);
7818   egraph->mdl.fval_maker = fval;
7819 
7820   egraph_collect_root_classes(egraph);
7821 
7822   // assign a value to all root classes
7823   egraph_model_for_root_classes(egraph, vtbl);
7824 }
7825 
7826 
7827 
7828 /*
7829  * Free/reset internal structures
7830  */
egraph_free_model(egraph_t * egraph)7831 void egraph_free_model(egraph_t *egraph) {
7832   if (egraph->fun_eg != NULL) {
7833     egraph->fun_eg->free_model(egraph->th[ETYPE_FUNCTION]);
7834   }
7835   reset_egraph_model(&egraph->mdl);
7836 }
7837