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