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 * SOLVER FOR FUNCTION/ARRAY THEORY
21 */
22
23 /*
24 * Optimization in final check:
25 * - We consider the following equivalence relation between composite terms
26 * in the egraph:
27 * (apply f t_1 ... t_n) may conflict with (apply g u_1 ... u_n)
28 * if t_1 == u_1 ... t_n == u_n (in the egraph)
29 * and (apply f t_1 ... t_n) is not in the same class as
30 * (apply g u_1 ... u_n) in the egraph.
31 *
32 * - When we check for conflict or extensionality instances, we
33 * don't need to consider (apply f t_1 ... t_n) if there's
34 * no composite that may conflict with it.
35 */
36
37 #include <inttypes.h>
38
39 #include "io/tracer.h"
40 #include "model/fun_trees.h"
41 #include "solvers/funs/fun_solver.h"
42 #include "utils/hash_functions.h"
43 #include "utils/index_vectors.h"
44 #include "utils/int_array_sort2.h"
45 #include "utils/int_hash_classes.h"
46 #include "utils/memalloc.h"
47 #include "utils/pointer_vectors.h"
48 #include "utils/ptr_array_sort2.h"
49 #include "utils/ptr_partitions.h"
50
51
52 #define TRACE 0
53
54 #if TRACE
55
56 #include <stdio.h>
57
58 #include "solvers/cdcl/smt_core_printer.h"
59 #include "solvers/egraph/egraph_printer.h"
60 #include "solvers/funs/fun_solver_printer.h"
61
62 #endif
63
64
65
66 /**********************
67 * EDGE DESCRIPTORS *
68 *********************/
69
70 /*
71 * Allocate an edge object of arity n
72 */
new_edge(uint32_t n)73 static inline fun_edge_t *new_edge(uint32_t n) {
74 assert(n <= MAX_COMPOSITE_ARITY);
75 return (fun_edge_t *) safe_malloc(sizeof(fun_edge_t) + n * sizeof(occ_t));
76 }
77
78
79 /*
80 * Create the edge for an update composite u
81 * - x = source variable
82 * - y = target variable
83 * - u = update composite
84 */
make_edge(thvar_t x,thvar_t y,composite_t * u)85 static fun_edge_t *make_edge(thvar_t x, thvar_t y, composite_t *u) {
86 fun_edge_t *e;
87 uint32_t i, n;
88
89 assert(composite_kind(u) == COMPOSITE_UPDATE && composite_arity(u) >= 3);
90
91 // u is (update f i_1 ... i_n v) where i_1,..., i_n are the edge labels
92 n = composite_arity(u) - 2;
93 e = new_edge(n);
94 e->source = x;
95 e->target = y;
96 for (i=0; i<n; i++) {
97 e->index[i] = composite_child(u, i+1);
98 }
99 return e;
100 }
101
102
103
104
105
106
107 /****************
108 * EDGE TABLE *
109 ***************/
110
111 /*
112 * Initialize: default size
113 */
init_edge_table(fun_edgetable_t * table)114 static void init_edge_table(fun_edgetable_t *table) {
115 assert(DEF_FUN_EDGETABLE_SIZE < MAX_FUN_EDGETABLE_SIZE);
116
117 table->size = DEF_FUN_EDGETABLE_SIZE;
118 table->nedges = 0;
119 table->data = (fun_edge_t **) safe_malloc(DEF_FUN_EDGETABLE_SIZE * sizeof(fun_edge_t *));
120 }
121
122
123 /*
124 * Make the table 50% larger
125 */
extend_edge_table(fun_edgetable_t * table)126 static void extend_edge_table(fun_edgetable_t *table) {
127 uint32_t n;
128
129 n = table->size + 1;
130 n += n>>1;
131 if (n >= MAX_FUN_EDGETABLE_SIZE) {
132 out_of_memory();
133 }
134 table->data = (fun_edge_t **) safe_realloc(table->data, n * sizeof(fun_edge_t *));
135 table->size = n;
136 }
137
138
139 /*
140 * Remove all edges of index >= n
141 */
shrink_edge_table(fun_edgetable_t * table,uint32_t n)142 static void shrink_edge_table(fun_edgetable_t *table, uint32_t n) {
143 uint32_t i, m;
144
145 assert(n <= table->nedges);
146
147 m = table->nedges;
148 for (i=n; i<m; i++) {
149 safe_free(table->data[i]);
150 }
151 table->nedges = n;
152 }
153
154
155 /*
156 * Empty the table: delete all edge objects
157 */
reset_edge_table(fun_edgetable_t * table)158 static void reset_edge_table(fun_edgetable_t *table) {
159 shrink_edge_table(table, 0);
160 }
161
162
163 /*
164 * Delete the table
165 */
delete_edge_table(fun_edgetable_t * table)166 static void delete_edge_table(fun_edgetable_t *table) {
167 shrink_edge_table(table, 0);
168 safe_free(table->data);
169 table->data = NULL;
170 }
171
172
173 /*
174 * Allocate a new edge index i
175 * - data[i] is not initialized
176 */
edge_table_alloc(fun_edgetable_t * table)177 static int32_t edge_table_alloc(fun_edgetable_t *table) {
178 uint32_t i;
179
180 i = table->nedges;
181 if (i == table->size) {
182 extend_edge_table(table);
183 }
184 assert(i < table->size);
185 table->nedges = i+1;
186
187 return i;
188 }
189
190
191
192
193
194
195 /********************
196 * VARIABLE TABLE *
197 *******************/
198
199 /*
200 * Initialize table with default size
201 */
init_fun_vartable(fun_vartable_t * table)202 static void init_fun_vartable(fun_vartable_t *table) {
203 uint32_t n;
204
205 assert(DEF_FUN_VARTABLE_SIZE < MAX_FUN_VARTABLE_SIZE);
206
207 n = DEF_FUN_VARTABLE_SIZE;
208 table->size = n;
209 table->nvars = 0;
210 table->type = (type_t *) safe_malloc(n * sizeof(type_t));
211 table->arity = (uint32_t *) safe_malloc(n * sizeof(uint32_t));
212 table->fdom = allocate_bitvector(n);
213 table->eterm = (eterm_t *) safe_malloc(n * sizeof(eterm_t));
214 table->edges = (int32_t **) safe_malloc(n * sizeof(int32_t *));
215 table->root = (thvar_t *) safe_malloc(n * sizeof(thvar_t));
216 table->next = (thvar_t *) safe_malloc(n * sizeof(thvar_t));
217 table->pre = (int32_t *) safe_malloc(n * sizeof(int32_t));
218 table->base = (int32_t *) safe_malloc(n * sizeof(int32_t));
219 table->app = (void ***) safe_malloc(n * sizeof(void **));
220 table->mark = allocate_bitvector(n);
221 }
222
223
224 /*
225 * Make the table 50% larger
226 */
extend_fun_vartable(fun_vartable_t * table)227 static void extend_fun_vartable(fun_vartable_t *table) {
228 uint32_t n;
229
230 n = table->size + 1;
231 n += n>>1;
232 if (n >= MAX_FUN_VARTABLE_SIZE) {
233 out_of_memory();
234 }
235
236 table->type = (type_t *) safe_realloc(table->type, n * sizeof(type_t));
237 table->arity = (uint32_t *) safe_realloc(table->arity, n * sizeof(uint32_t));
238 table->fdom = extend_bitvector(table->fdom, n);
239 table->eterm = (eterm_t *) safe_realloc(table->eterm, n * sizeof(eterm_t));
240 table->edges = (int32_t **) safe_realloc(table->edges, n * sizeof(int32_t *));
241 table->root = (thvar_t *) safe_realloc(table->root, n * sizeof(thvar_t));
242 table->next = (thvar_t *) safe_realloc(table->next, n * sizeof(thvar_t));
243 table->pre = (int32_t *) safe_realloc(table->pre, n * sizeof(int32_t));
244 table->base = (int32_t *) safe_realloc(table->base, n * sizeof(int32_t));
245 table->app = (void ***) safe_realloc(table->app, n * sizeof(void **));
246 table->mark = extend_bitvector(table->mark, n);
247 table->size = n;
248 }
249
250
251 /*
252 * Remove all variables of index >= n
253 */
shrink_fun_vartable(fun_vartable_t * table,uint32_t n)254 static void shrink_fun_vartable(fun_vartable_t *table, uint32_t n) {
255 uint32_t i, m;
256
257 m = table->nvars;
258 assert(n <= m);
259 for (i=n; i<m; i++) {
260 delete_index_vector(table->edges[i]);
261 }
262 table->nvars = n;
263 }
264
265
266 /*
267 * Empty the table
268 */
reset_fun_vartable(fun_vartable_t * table)269 static void reset_fun_vartable(fun_vartable_t *table) {
270 shrink_fun_vartable(table, 0);
271 }
272
273
274 /*
275 * Delete the table
276 */
delete_fun_vartable(fun_vartable_t * table)277 static void delete_fun_vartable(fun_vartable_t *table) {
278 shrink_fun_vartable(table, 0);
279
280 safe_free(table->type);
281 safe_free(table->arity);
282 delete_bitvector(table->fdom);
283 safe_free(table->eterm);
284 safe_free(table->edges);
285 safe_free(table->root);
286 safe_free(table->next);
287 safe_free(table->pre);
288 safe_free(table->base);
289 safe_free(table->app);
290 delete_bitvector(table->mark);
291
292 table->type = NULL;
293 table->arity = NULL;
294 table->fdom = NULL;
295 table->eterm = NULL;
296 table->edges = NULL;
297 table->root = NULL;
298 table->next = NULL;
299 table->pre = NULL;
300 table->base = NULL;
301 table->app = NULL;
302 table->mark = NULL;
303 }
304
305
306 /*
307 * Allocate a new variable index x
308 * - type, arity, etc. are not initialized
309 */
fun_vartable_alloc(fun_vartable_t * table)310 static thvar_t fun_vartable_alloc(fun_vartable_t *table) {
311 uint32_t i;
312
313 i = table->nvars;
314 if (i == table->size) {
315 extend_fun_vartable(table);
316 }
317 table->nvars = i+1;
318
319 return i;
320 }
321
322
323
324 /*
325 * Check type of variable x
326 */
fun_var_type(fun_vartable_t * table,thvar_t x)327 static inline type_t fun_var_type(fun_vartable_t *table, thvar_t x) {
328 assert(0 <= x && x < table->nvars);
329 return table->type[x];
330 }
331
332
333 /*
334 * Check whether variable x has a finite domain
335 */
fun_var_has_finite_domain(fun_vartable_t * table,thvar_t x)336 static inline bool fun_var_has_finite_domain(fun_vartable_t *table, thvar_t x) {
337 assert(0 <= x && x < table->nvars);
338 return tst_bit(table->fdom, x);
339 }
340
fun_var_has_infinite_domain(fun_vartable_t * table,thvar_t x)341 static inline bool fun_var_has_infinite_domain(fun_vartable_t *table, thvar_t x) {
342 return ! fun_var_has_finite_domain(table, x);
343 }
344
345
346
347
348 /***********
349 * QUEUE *
350 **********/
351
352 /*
353 * Initialization: use default size
354 */
init_fun_queue(fun_queue_t * queue)355 static void init_fun_queue(fun_queue_t *queue) {
356 uint32_t n;
357
358 n = DEF_FUN_QUEUE_SIZE;
359 assert(n < MAX_FUN_QUEUE_SIZE);
360
361 queue->size = n;
362 queue->top = 0;
363 queue->ptr = 0;
364 queue->data = (thvar_t *) safe_malloc(n * sizeof(thvar_t));
365 }
366
367
368 /*
369 * Make the queue 50% larger
370 */
extend_fun_queue(fun_queue_t * queue)371 static void extend_fun_queue(fun_queue_t *queue) {
372 uint32_t n;
373
374 n = queue->size + 1;
375 n += n>>1;
376 if (n >= MAX_FUN_QUEUE_SIZE) {
377 out_of_memory();
378 }
379
380 queue->data = (thvar_t *) safe_realloc(queue->data, n * sizeof(thvar_t));
381 queue->size = n;
382 }
383
384
385 /*
386 * Delete the queue
387 */
delete_fun_queue(fun_queue_t * queue)388 static void delete_fun_queue(fun_queue_t *queue) {
389 safe_free(queue->data);
390 queue->data = NULL;
391 }
392
393
394 /*
395 * Reset the queue
396 */
reset_fun_queue(fun_queue_t * queue)397 static void reset_fun_queue(fun_queue_t *queue) {
398 queue->top = 0;
399 queue->ptr = 0;
400 }
401
402
403 /*
404 * Push a vertex x at the end of the queue
405 */
fun_queue_push(fun_queue_t * queue,thvar_t x)406 static void fun_queue_push(fun_queue_t *queue, thvar_t x) {
407 uint32_t i;
408
409 i = queue->top;
410 if (i == queue->size) {
411 extend_fun_queue(queue);
412 }
413 assert(i < queue->size);
414 queue->data[i] = x;
415 queue->top = i+1;
416 }
417
418
419 /*
420 * Check whether the queue is empty
421 */
empty_fun_queue(fun_queue_t * queue)422 static inline bool empty_fun_queue(fun_queue_t *queue) {
423 return queue->top == queue->ptr;
424 }
425
426
427 /*
428 * Get the first element of the queue and increment ptr
429 */
fun_queue_pop(fun_queue_t * queue)430 static thvar_t fun_queue_pop(fun_queue_t *queue) {
431 uint32_t i;
432 thvar_t x;
433
434 i = queue->ptr;
435 assert(i < queue->top);
436 x = queue->data[i];
437 queue->ptr = i+1;
438
439 return x;
440 }
441
442
443
444
445
446
447
448 /*********************
449 * PUSH/POP STACK *
450 ********************/
451
452 /*
453 * Initialize the stack
454 */
init_fun_trail_stack(fun_trail_stack_t * stack)455 static void init_fun_trail_stack(fun_trail_stack_t *stack) {
456 assert(DEF_FUN_TRAIL_SIZE < MAX_FUN_TRAIL_SIZE);
457
458 stack->size = DEF_FUN_TRAIL_SIZE;
459 stack->top = 0;
460 stack->data = (fun_trail_t *) safe_malloc(DEF_FUN_TRAIL_SIZE * sizeof(fun_trail_t));
461 }
462
463
464 /*
465 * Make the stack 50% larger
466 */
extend_fun_trail_stack(fun_trail_stack_t * stack)467 static void extend_fun_trail_stack(fun_trail_stack_t *stack) {
468 uint32_t n;
469
470 n = stack->size + 1;
471 n += n >> 1;
472 if (n >= MAX_FUN_TRAIL_SIZE) {
473 out_of_memory();
474 }
475
476 stack->data = (fun_trail_t *) safe_realloc(stack->data, n * sizeof(fun_trail_t));
477 stack->size = n;
478 }
479
480
481 /*
482 * Empty the stack
483 */
reset_fun_trail_stack(fun_trail_stack_t * stack)484 static inline void reset_fun_trail_stack(fun_trail_stack_t *stack) {
485 stack->top = 0;
486 }
487
488
489 /*
490 * Delete the stack
491 */
delete_fun_trail_stack(fun_trail_stack_t * stack)492 static void delete_fun_trail_stack(fun_trail_stack_t *stack) {
493 safe_free(stack->data);
494 stack->data = NULL;
495 }
496
497
498 /*
499 * Save data for the current base level:
500 * - nv = number of variables
501 * - ne = number of edges
502 */
fun_trail_stack_save(fun_trail_stack_t * stack,uint32_t nv,uint32_t ne)503 static void fun_trail_stack_save(fun_trail_stack_t *stack, uint32_t nv, uint32_t ne) {
504 uint32_t i;
505
506 i = stack->top;
507 if (i == stack->size) {
508 extend_fun_trail_stack(stack);
509 }
510 assert(i < stack->size);
511 stack->data[i].nvars = nv;
512 stack->data[i].nedges = ne;
513 stack->top = i + 1;
514 }
515
516
517 /*
518 * Get the top record
519 */
fun_trail_stack_top(fun_trail_stack_t * stack)520 static inline fun_trail_t *fun_trail_stack_top(fun_trail_stack_t *stack) {
521 assert(stack->top > 0);
522 return stack->data + (stack->top - 1);
523 }
524
525
526 /*
527 * Remove the top record
528 */
fun_trail_stack_pop(fun_trail_stack_t * stack)529 static inline void fun_trail_stack_pop(fun_trail_stack_t *stack) {
530 assert(stack->top > 0);
531 stack->top --;
532 }
533
534
535
536
537 /**********************
538 * STATISTIC RECORD *
539 *********************/
540
init_fun_solver_statistics(fun_solver_stats_t * stat)541 static void init_fun_solver_statistics(fun_solver_stats_t *stat) {
542 stat->num_init_vars = 0;
543 stat->num_init_edges = 0;
544 stat->num_update_axiom1 = 0;
545 stat->num_update_axiom2 = 0;
546 stat->num_extensionality_axiom = 0;
547 }
548
reset_fun_solver_statistics(fun_solver_stats_t * stat)549 static inline void reset_fun_solver_statistics(fun_solver_stats_t *stat) {
550 init_fun_solver_statistics(stat);
551 }
552
553
554
555
556
557 /*******************
558 * VALUE VECTOR *
559 ******************/
560
561 /*
562 * Allocate and initialize the value vector:
563 * - its size is the number of variables
564 * - value[x] is set to NULL for all x
565 */
fun_solver_init_values(fun_solver_t * solver)566 static void fun_solver_init_values(fun_solver_t *solver) {
567 map_t **tmp;
568 uint32_t i, n;
569
570 assert(solver->value == NULL);
571
572 n = solver->vtbl.nvars;
573 tmp = (map_t **) safe_malloc(n * sizeof(map_t *));
574 for (i=0; i<n; i++) {
575 tmp[i] = NULL;
576 }
577 solver->value = tmp;
578 solver->value_size = n;
579 }
580
581
582 /*
583 * Delete the value vector and all the maps it contains.
584 */
fun_solver_delete_values(fun_solver_t * solver)585 static void fun_solver_delete_values(fun_solver_t *solver) {
586 map_t **v;
587 uint32_t i, n;
588
589 assert(solver->value != NULL);
590
591 v = solver->value;
592 n = solver->value_size;
593 for (i=0; i<n; i++) {
594 if (v[i] != NULL) {
595 free_map(v[i]);
596 }
597 }
598
599 safe_free(v);
600
601 solver->value = NULL;
602 solver->value_size = 0;
603 }
604
605
606
607 /*
608 * Allocate and initialize the base_map vector
609 * - its size = n (should be equal to num_bases)
610 * - base_map[i] is initialized to NULL for all connected components
611 */
fun_solver_init_base_maps(fun_solver_t * solver,uint32_t n)612 static void fun_solver_init_base_maps(fun_solver_t *solver, uint32_t n) {
613 map_t **tmp;
614 uint32_t i;
615
616 assert(solver->base_map == NULL);
617
618 tmp = (map_t **) safe_malloc(n * sizeof(map_t *));
619 for (i=0; i<n; i++) {
620 tmp[i] = NULL;
621 }
622 solver->base_map = tmp;
623 solver->base_map_size = n;
624 }
625
626
627 /*
628 * Delete the base_map vector and all the maps it contains
629 */
fun_solver_delete_base_maps(fun_solver_t * solver)630 static void fun_solver_delete_base_maps(fun_solver_t *solver) {
631 map_t **v;
632 uint32_t i, n;
633
634 assert(solver->base_map != NULL);
635
636 v = solver->base_map;
637 n = solver->base_map_size;
638 for (i=0; i<n; i++) {
639 if (v[i] != NULL) {
640 free_map(v[i]);
641 }
642 }
643 safe_free(v);
644
645 solver->base_map = NULL;
646 solver->base_map_size = 0;
647 }
648
649
650
651 /*
652 * HASH MAP FOR FRESH PARTICLES
653 */
654
655 /*
656 * Return the map. allocate and initialize it if necessary
657 */
fun_solver_get_fresh_hmap(fun_solver_t * solver)658 static int_hmap2_t *fun_solver_get_fresh_hmap(fun_solver_t *solver) {
659 int_hmap2_t *map;
660
661 map = solver->fresh_hmap;
662 if (map == NULL) {
663 map = (int_hmap2_t *) safe_malloc(sizeof(int_hmap2_t));
664 init_int_hmap2(map, 0); // use the default size
665 solver->fresh_hmap = map;
666 }
667
668 return map;
669 }
670
671
672 /*
673 * Delete the map if it exists
674 */
fun_solver_delete_fresh_hmap(fun_solver_t * solver)675 static void fun_solver_delete_fresh_hmap(fun_solver_t *solver) {
676 int_hmap2_t *map;
677
678 map = solver->fresh_hmap;
679 if (map != NULL) {
680 delete_int_hmap2(map);
681 safe_free(map);
682 solver->fresh_hmap = NULL;
683 }
684 }
685
686
687
688 /***************************************
689 * UTILITIES FOR EXPLORING THE GRAPH *
690 **************************************/
691
692 /*
693 * Edge descriptor of edge i
694 */
get_edge(fun_edgetable_t * table,int32_t i)695 static inline fun_edge_t *get_edge(fun_edgetable_t *table, int32_t i) {
696 assert(0 <= i && i < table->nedges);
697 return table->data[i];
698 }
699
700 /*
701 * Node adjacent to x via edge i
702 * - x must be either the source or the target of edge i
703 */
adjacent_node(fun_edgetable_t * table,thvar_t x,int32_t i)704 static thvar_t adjacent_node(fun_edgetable_t *table, thvar_t x, int32_t i) {
705 fun_edge_t *e;
706
707 e = get_edge(table, i);
708 assert(e->source == x || e->target == x);
709 return e->source ^ e->target ^ x;
710 }
711
712
713 /*
714 * Root of the node adjacent to x via edge i
715 */
adjacent_root(fun_solver_t * solver,thvar_t x,int32_t i)716 static inline thvar_t adjacent_root(fun_solver_t *solver, thvar_t x, int32_t i) {
717 return solver->vtbl.root[adjacent_node(&solver->etbl, x, i)];
718 }
719
720
721 /*
722 * Predecessor of x
723 * - get the root var y that precedes root var x via edge i
724 * - i = vtbl->pre[x] must be the edge id for an edge u <---> t with
725 * t in class of x and u in class of y
726 */
previous_root(fun_solver_t * solver,thvar_t x,int32_t i)727 static thvar_t previous_root(fun_solver_t *solver, thvar_t x, int32_t i) {
728 fun_edge_t *e;
729 thvar_t y, z;
730
731 e = get_edge(&solver->etbl, i);
732 y = solver->vtbl.root[e->source];
733 z = solver->vtbl.root[e->target];
734 assert(x == y || x == z);
735 return (x == y) ? z : y;
736 }
737
738
739 /*
740 * Node in class of x that's the real source or target of edge i
741 * - x must be a root variable
742 * - i must be the index of an edge whose source or target has root x
743 */
node_for_root(fun_solver_t * solver,thvar_t x,int32_t i)744 static thvar_t node_for_root(fun_solver_t *solver, thvar_t x, int32_t i) {
745 fun_edge_t *e;
746
747 e = get_edge(&solver->etbl, i);
748 if (solver->vtbl.root[e->source] == x) {
749 return e->source;
750 } else {
751 assert(solver->vtbl.root[e->target] == x);
752 return e->target;
753 }
754 }
755
756
757
758
759
760
761 /***************************
762 * ARRAY/FUNCTION AXIOMS *
763 **************************/
764
765 /*
766 * AXIOM 1: ((update f i_1 ... i_n v) i_1 ... i_n) == v
767 */
768
769 /*
770 * Create an instance of update axiom 1:
771 * - u must be (update f i_1 ... i_n v)
772 * - t must be the term whose body is u
773 * - tau is the type of u (and t)
774 */
fun_solver_update_axiom1(fun_solver_t * solver,eterm_t t,composite_t * u,type_t tau)775 static void fun_solver_update_axiom1(fun_solver_t *solver, eterm_t t, composite_t *u, type_t tau) {
776 egraph_t *egraph;
777 ivector_t *v;
778 uint32_t i, n;
779 eterm_t a;
780 literal_t eq;
781
782 // t is (update f i_1 ... i_n v)
783 assert(composite_kind(u) == COMPOSITE_UPDATE && composite_arity(u) >= 3 && u->id == t);
784
785 egraph = solver->egraph;
786
787 // create (t i_1 ... i_n)
788 v = &solver->aux_vector;
789 assert(v->size == 0);
790 n = composite_arity(u) - 2;
791 for (i=0; i<n; i++) {
792 ivector_push(v, composite_child(u, i+1));
793 }
794 a = egraph_make_apply(egraph, pos_occ(t), n, v->data, function_type_range(solver->types, tau));
795
796 // assert the equality (a == v)
797 if (solver->decision_level == solver->base_level) {
798 egraph_assert_eq_axiom(egraph, pos_occ(a), composite_child(u, n+1));
799 } else {
800 eq = egraph_make_eq(egraph, pos_occ(a), composite_child(u, n+1));
801 add_unit_clause(solver->core, eq);
802 }
803
804 // cleanup
805 ivector_reset(v);
806
807 // increment counter
808 solver->stats.num_update_axiom1 ++;
809 }
810
811
812
813
814 /*
815 * UPDATE AXIOM 2: GENERALIZED FORM
816 *
817 * Instances are created from two terms (f i_1 ... i_n) and (g j_1 ... j_n) and
818 * a path in the graph from a source x to a target variable y. The path is formed
819 * of a list of edges (x_1 --> y_1) ... (x_t --> y_t) with the following property:
820 * - y_k is in the class of x_{k+1} for k= 1,.., t-1
821 * - f is in the class of variable x_1 = class of x
822 * - g is in the class of variable y_t = class of y
823 *
824 * Let [k_11 ... k_1n], ..., [k_t1 ... k_tn] be the labels on the successive edges,
825 * and let u_i = eterm[x_i] and v_i = eterm[y_i] then the instance derived from
826 * (f i_1 ... i_n) and (g j_1 ... j_n) is of the form:
827 *
828 * (f = u_1 and v_1 = u_2 ... v_{t-1} = u_t and v_t = g and i_1 = j_1 ... i_n = j_n)
829 * and (not (i_1 = k_11 and ... and i_n = k_1n))
830 * ...
831 * and (not (i_1 = k_t1 and ... and i_n = k_tn))
832 * implies (f i_1 ... i_n) = (g j_1 ... j_n)
833 *
834 */
835
836
837 /*
838 * Given two composites
839 * - c = (apply f i_1 ... i_n)
840 * - d = (apply g j_1 ... j_n),
841 * add the atoms (i_1 = j_1) ... (i_n = j_n) to vector *v.
842 * (skip the trivial atoms where i_t and j_t are equal).
843 */
collect_equal_arg_atoms(fun_solver_t * solver,composite_t * c,composite_t * d,ivector_t * v)844 static void collect_equal_arg_atoms(fun_solver_t *solver, composite_t *c, composite_t *d, ivector_t *v) {
845 egraph_t *egraph;
846 uint32_t i, n;
847 occ_t u1, u2;
848 literal_t l;
849
850 assert(composite_kind(c) == COMPOSITE_APPLY && composite_kind(d) == COMPOSITE_APPLY &&
851 composite_arity(c) == composite_arity(d));
852
853 egraph = solver->egraph;
854 n = composite_arity(c);
855 assert (n >= 2);
856 for (i=1; i<n; i++) {
857 u1 = composite_child(c, i);
858 u2 = composite_child(d, i);
859 if (u1 != u2) {
860 l = egraph_make_eq(egraph, u1, u2);
861 ivector_push(v, l);
862 }
863 }
864 }
865
866
867 /*
868 * Given
869 * - c = (apply f i_1 ... i_n)
870 * - x = a root variable
871 * - k = an edge index
872 * add the atom (f = u) to vector v, where u = term attached to the extremity of k
873 * that's in the same class as x.
874 */
add_equal_fun_and_node_atom(fun_solver_t * solver,composite_t * c,thvar_t x,int32_t k,ivector_t * v)875 static void add_equal_fun_and_node_atom(fun_solver_t *solver, composite_t *c, thvar_t x, int32_t k, ivector_t *v) {
876 thvar_t y;
877 occ_t f, u;
878 literal_t l;
879
880 assert(composite_kind(c) == COMPOSITE_APPLY && composite_arity(c) >= 1);
881
882 f = composite_child(c, 0);
883 y = node_for_root(solver, x, k);
884 assert(solver->vtbl.eterm[y] != null_eterm);
885 u = pos_occ(solver->vtbl.eterm[y]);
886 if (f != u) {
887 l = egraph_make_eq(solver->egraph, f, u);
888 ivector_push(v, l);
889 }
890 }
891
892
893 /*
894 * Given the composites c and d and a source var x and target var y
895 * collect the atoms for the path from x to y: add all atoms to vector v.
896 */
collect_path_atoms(fun_solver_t * solver,thvar_t x,thvar_t y,composite_t * c,composite_t * d,ivector_t * v)897 static void collect_path_atoms(fun_solver_t *solver, thvar_t x, thvar_t y, composite_t *c, composite_t *d, ivector_t *v) {
898 fun_vartable_t *vtbl;
899 egraph_t *egraph;
900 thvar_t z, u;
901 literal_t l;
902 int32_t k;
903
904 egraph = solver->egraph;
905 vtbl = &solver->vtbl;
906
907 // end node: y. add the constraint (g == extremity of edge k in class of y)
908 k = vtbl->pre[y];
909 assert(k >= 0 && k != null_fun_pred);
910 add_equal_fun_and_node_atom(solver, d, y, k, v);
911
912 // intermediate nodes
913 y = previous_root(solver, y, k);
914 while (y != x) {
915 z = node_for_root(solver, y, k); // extremity of edge k in class of y
916 k = vtbl->pre[y]; // previous edge on the path
917 u = node_for_root(solver, y, k); // extremity of that edge in class of y
918 assert(vtbl->root[z] == y && vtbl->root[u] == y);
919 if (u != z) {
920 l = egraph_make_eq(egraph, pos_occ(vtbl->eterm[z]), pos_occ(vtbl->eterm[u]));
921 ivector_push(v, l);
922 }
923 y = previous_root(solver, y, k);
924 }
925
926 // source node: x. add the constraint (f == extremity of edge k in class of x)
927 add_equal_fun_and_node_atom(solver, c, x, k, v);
928 }
929
930
931
932 /*
933 * Create the conjunct (i_1 == j_1 and ... and i_n == j_n) for an apply term and an edge
934 * - c must be (apply f i_1 ... i_n) for some f
935 * - e must be an edge with label [j_1 ... j_n]
936 */
apply_edge_equal_args(fun_solver_t * solver,composite_t * c,fun_edge_t * e)937 static literal_t apply_edge_equal_args(fun_solver_t *solver, composite_t *c, fun_edge_t *e) {
938 egraph_t *egraph;
939 ivector_t *v;
940 uint32_t i, n;
941 literal_t l;
942
943 assert(composite_kind(c) == COMPOSITE_APPLY &&
944 composite_arity(c) == 1 + solver->vtbl.arity[e->source]);
945
946 egraph = solver->egraph;
947 n = composite_arity(c);
948 if (n == 2) {
949 l = egraph_make_eq(egraph, composite_child(c, 1), e->index[0]);
950
951 #if TRACE
952 printf("edge constraint: f!%"PRId32" --> f!%"PRId32"\n", e->source, e->target);
953 print_literal(stdout, l);
954 printf(" := ");
955 print_egraph_atom_of_literal(stdout, egraph, l);
956 printf("\n");
957 #endif
958
959 } else {
960 assert(n >= 3);
961 v = &solver->aux_vector;
962 assert(v->size == 0);
963 for (i=1; i<n; i++) {
964 l = egraph_make_eq(egraph, composite_child(c, i), e->index[i-1]);
965 ivector_push(v, l);
966 }
967 l = mk_and_gate(solver->gate_manager, v->size, v->data);
968
969 #if TRACE
970 printf("edge constraint: f!%"PRId32" --> f!%"PRId32"\n", e->source, e->target);
971 print_literal(stdout, l);
972 printf(" := (AND");
973 for (i=0; i<v->size; i++) {
974 print_egraph_atom_of_literal(stdout, egraph, v->data[i]);
975 }
976 printf(")\n");
977 #endif
978
979 ivector_reset(v);
980 }
981
982 return l;
983 }
984
985
986
987 /*
988 * Construct the atom (eq (f i_1 ... i_n) (g j_1 ... j_n)) for two apply terms
989 * - c = (f i_1 ... i_n)
990 * - d = (g j_1 ... j_n)
991 */
equal_applies(fun_solver_t * solver,composite_t * c,composite_t * d)992 static inline literal_t equal_applies(fun_solver_t *solver, composite_t *c, composite_t *d) {
993 return egraph_make_eq(solver->egraph, pos_occ(c->id), pos_occ(d->id));
994 }
995
996
997
998
999
1000
1001
1002 /*
1003 * EXTENSIONALITY AXIOM
1004 *
1005 * The axiom for two variables f and g is
1006 * (OR (= f g) (/= (f i_1 ... i_n) (g i_1 ... i_n)))
1007 * where i_1, ..., i_n are fresh skolem constants.
1008 */
1009
1010 /*
1011 * Create fresh skolem constants in the egraph for the domain of type tau
1012 * - tau must be a function type
1013 * - the skolem constants are added to vector v (as a vector of egraph occurrences)
1014 */
fun_solver_skolem_domain(fun_solver_t * solver,type_t tau,ivector_t * v)1015 static void fun_solver_skolem_domain(fun_solver_t *solver, type_t tau, ivector_t *v) {
1016 function_type_t *d;
1017 egraph_t *egraph;
1018 uint32_t i, n;
1019 eterm_t t;
1020
1021 egraph = solver->egraph;
1022 d = function_type_desc(solver->types, tau);
1023 n = d->ndom;
1024 for (i=0; i<n; i++) {
1025 t = egraph_make_variable(egraph, d->domain[i]);
1026 ivector_push(v, pos_occ(t));
1027 }
1028 }
1029
1030
1031 /*
1032 * Range of variable x:
1033 * - x has function type tau = [tau_1 ... tau_n --> sigma]
1034 * - the range is sigma
1035 */
fun_var_range_type(fun_solver_t * solver,thvar_t x)1036 static inline type_t fun_var_range_type(fun_solver_t *solver, thvar_t x) {
1037 return function_type_range(solver->types, solver->vtbl.type[x]);
1038 }
1039
1040 /*
1041 * Create the extensionality axiom for (x != y)
1042 * - x and y must have the same domain
1043 */
fun_solver_extensionality_axiom(fun_solver_t * solver,thvar_t x,thvar_t y)1044 static void fun_solver_extensionality_axiom(fun_solver_t *solver, thvar_t x, thvar_t y) {
1045 fun_vartable_t *vtbl;
1046 egraph_t *egraph;
1047 ivector_t *v;
1048 eterm_t t, u;
1049 literal_t l1, l2;
1050
1051 assert(0 <= x && x < solver->vtbl.nvars && 0 <= y && y < solver->vtbl.nvars && x != y);
1052
1053 egraph = solver->egraph;
1054 vtbl = &solver->vtbl;
1055 v = &solver->aux_vector;
1056 assert(v->size == 0);
1057 fun_solver_skolem_domain(solver, vtbl->type[x], v);
1058
1059 t = egraph_make_apply(egraph, pos_occ(vtbl->eterm[x]), v->size, v->data, fun_var_range_type(solver, x));
1060 u = egraph_make_apply(egraph, pos_occ(vtbl->eterm[y]), v->size, v->data, fun_var_range_type(solver, y));
1061 l1 = egraph_make_eq(egraph, pos_occ(t), pos_occ(u));
1062 l2 = egraph_make_eq(egraph, pos_occ(vtbl->eterm[x]), pos_occ(vtbl->eterm[y]));
1063
1064 #if 0
1065 printf("---> ARRAY SOLVER: extensionality axiom for f!%"PRId32" /= f!%"PRId32" ----\n", x, y);
1066 #endif
1067
1068 #if TRACE
1069 printf("\n---- Extensionality axiom for f!%"PRId32" /= f!%"PRId32" ----\n", x, y);
1070 print_eterm_def(stdout, solver->egraph, vtbl->eterm[x]);
1071 print_eterm_def(stdout, solver->egraph, vtbl->eterm[y]);
1072 printf("New terms:\n");
1073 print_eterm_def(stdout, egraph, t);
1074 print_eterm_def(stdout, egraph, u);
1075 printf("Atoms:\n");
1076 print_literal(stdout, l1);
1077 printf(" := ");
1078 print_egraph_atom_of_literal(stdout, egraph, l1);
1079 printf("\n");
1080 print_literal(stdout, l2);
1081 printf(" := ");
1082 print_egraph_atom_of_literal(stdout, egraph, l2);
1083 printf("\n");
1084 printf("Clause:\n");
1085 printf(" (OR ");
1086 print_literal(stdout, not(l1));
1087 printf(" ");
1088 print_literal(stdout, l2);
1089 printf(")\n\n");
1090 #endif
1091
1092 add_binary_clause(solver->core, not(l1), l2);
1093
1094 ivector_reset(v);
1095
1096 solver->stats.num_extensionality_axiom ++;
1097 }
1098
1099
1100
1101
1102 /************************************
1103 * COLLECT ROOTS AND APPLICATIONS *
1104 ***********************************/
1105
1106 /*
1107 * Find root variable for variable x
1108 * - we pick the theory variable in the egraph class of term of x
1109 */
root_var(fun_solver_t * solver,thvar_t x)1110 static inline thvar_t root_var(fun_solver_t *solver, thvar_t x) {
1111 egraph_t *egraph;
1112 eterm_t t;
1113
1114 assert(0 <= x && x < solver->vtbl.nvars);
1115 egraph = solver->egraph;
1116 t = solver->vtbl.eterm[x];
1117 return egraph_class_thvar(egraph, egraph_term_class(egraph, t));
1118 }
1119
1120
1121
1122 /*
1123 * Build the equivalence classes
1124 * - set root[x] for all variables
1125 * - construct the list of elements for every root variable x
1126 */
fun_solver_build_classes(fun_solver_t * solver)1127 static void fun_solver_build_classes(fun_solver_t *solver) {
1128 fun_vartable_t *vtbl;
1129 uint32_t i, n;
1130 thvar_t x;
1131
1132 // set the roots and initialize lists
1133 vtbl = &solver->vtbl;
1134 n = vtbl->nvars;
1135 for (i=0; i<n; i++) {
1136 x = root_var(solver, i);
1137 assert(x != null_thvar);
1138 vtbl->root[i] = x;
1139 if (x == i) {
1140 vtbl->next[i] = null_thvar;
1141 }
1142 }
1143
1144 // add all elements to the root's list
1145 for (i=0; i<n; i++) {
1146 x = vtbl->root[i];
1147 if (x != i) {
1148 vtbl->next[i] = vtbl->next[x];
1149 vtbl->next[x] = i;
1150 }
1151 }
1152
1153 }
1154
1155
1156 /*
1157 * Assign base label k to all root variables connected to x
1158 * (including x)
1159 * - x must be a root
1160 * - k must be non-negative
1161 */
fun_solver_label_component(fun_solver_t * solver,thvar_t x,int32_t k)1162 static void fun_solver_label_component(fun_solver_t *solver, thvar_t x, int32_t k) {
1163 fun_queue_t *queue;
1164 fun_vartable_t *vtbl;
1165 int32_t *edges;
1166 thvar_t y;
1167 uint32_t n, i;
1168 int32_t j;
1169
1170 vtbl = &solver->vtbl;
1171 queue = &solver->queue;
1172 assert(queue->top == 0 && queue->ptr == 0);
1173
1174 fun_queue_push(queue, x);
1175 vtbl->base[x] = k;
1176 while (! empty_fun_queue(queue)) {
1177 x = fun_queue_pop(queue);
1178 assert(vtbl->base[x] == k && vtbl->root[x] == x);
1179 do {
1180 // explore edges incident to x's class
1181 edges = vtbl->edges[x];
1182 if (edges != NULL) {
1183 n = iv_size(edges);
1184 for (i=0; i<n; i++) {
1185 j = edges[i];
1186 y = adjacent_root(solver, x, j);
1187 if (vtbl->base[y] < 0) {
1188 fun_queue_push(queue, y);
1189 vtbl->base[y] = k;
1190 }
1191 }
1192 }
1193 x = vtbl->next[x];
1194 } while (x != null_thvar);
1195 }
1196
1197 reset_fun_queue(queue);
1198 }
1199
1200
1201 /*
1202 * Compute the connected components
1203 * - all root variables in the same connected component are assigned the same label
1204 * (stored in base[x]).
1205 * - set bases_ready flag to true
1206 * - store the number of connected components in num_bases
1207 */
fun_solver_build_components(fun_solver_t * solver)1208 static void fun_solver_build_components(fun_solver_t *solver) {
1209 fun_vartable_t *vtbl;
1210 uint32_t i, n;
1211 int32_t l;
1212
1213 l = 0;
1214 vtbl = &solver->vtbl;
1215 n = vtbl->nvars;
1216 for (i=0; i<n; i++) {
1217 if (vtbl->root[i] == i && vtbl->base[i] < 0) {
1218 fun_solver_label_component(solver, i, l);
1219 l ++;
1220 }
1221 }
1222
1223 solver->bases_ready = true;
1224 solver->num_bases = l;
1225 }
1226
1227
1228
1229
1230 /*
1231 * Cleanup:
1232 * - delete the vectors vtbl->app[x] for all roots
1233 * - reset vtbl->base[x] to -1
1234 * - reset apps_ready and bases_ready to false
1235 */
fun_solver_cleanup(fun_solver_t * solver)1236 static void fun_solver_cleanup(fun_solver_t *solver) {
1237 fun_vartable_t *vtbl;
1238 uint32_t i, n;
1239
1240 vtbl = &solver->vtbl;
1241 n = vtbl->nvars;
1242 for (i=0; i<n; i++) {
1243 if (vtbl->root[i] == i) {
1244 delete_ptr_vector(vtbl->app[i]);
1245 vtbl->app[i] = NULL;
1246 vtbl->base[i] = -1;
1247 }
1248 assert(vtbl->base[i] == -1 && vtbl->app[i] == NULL);
1249 }
1250
1251 solver->apps_ready = false;
1252 solver->bases_ready = false;
1253 }
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263 /***********************************************
1264 * EQUIVALENCE AND ORDER BETWEEN APPLY TERMS *
1265 **********************************************/
1266
1267 /*
1268 * For each root variable x, we store a set of apply terms in app[x].
1269 * This set encodes what is known about x as a partial mapping.
1270 * If (f i_1 ... i_n) has egraph label C and belongs to app[x]
1271 * then x maps the tuple (L(i_1) ... L(i_n)) to C, where
1272 * L(i_k) is the label of i_k in the egraph.
1273 *
1274 * To normalize app[x], we sort the set using the order:
1275 * (f i_1 ... i_n) <= (g j_1 ... j_n) if
1276 * [L(i_1), ... ,L(i_n)] <= [L(j_1), ..., L(j_n)] in lexicographic order.
1277 *
1278 * Two apply terms (f i_1 ... i_n) and (g j_1 ... j_n) are equivalent if
1279 * L(i_1) = L(j_1) ... L(i_n) = L(j_n).
1280 */
1281
1282 /*
1283 * Test whether c and d are equivalent
1284 */
app_equiv(egraph_t * egraph,composite_t * c,composite_t * d)1285 static bool app_equiv(egraph_t *egraph, composite_t *c, composite_t *d) {
1286 uint32_t i, n;
1287
1288 assert(composite_kind(c) == COMPOSITE_APPLY && composite_kind(d) == COMPOSITE_APPLY &&
1289 composite_arity(c) == composite_arity(d));
1290
1291 n = composite_arity(c);
1292 for (i=1; i<n; i++) {
1293 if (! egraph_equal_occ(egraph, composite_child(c, i), composite_child(d, i))) {
1294 return false;
1295 }
1296 }
1297 return true;
1298 }
1299
1300
1301 /*
1302 * Comparison between c and d:
1303 * - return a negative number if c < d
1304 * - return 0 if c = d
1305 * - return a positive number if c > d
1306 */
app_cmp(egraph_t * egraph,composite_t * c,composite_t * d)1307 static int32_t app_cmp(egraph_t *egraph, composite_t *c, composite_t *d) {
1308 uint32_t i, n;
1309 elabel_t l1, l2;
1310
1311 assert(composite_kind(c) == COMPOSITE_APPLY && composite_kind(d) == COMPOSITE_APPLY &&
1312 composite_arity(c) == composite_arity(d));
1313
1314 n = composite_arity(c);
1315 for (i=1; i<n; i++) {
1316 l1 = egraph_label(egraph, composite_child(c, i));
1317 l2 = egraph_label(egraph, composite_child(d, i));
1318 if (l1 != l2) {
1319 return (l1 - l2); // negative if l1 < l2, positive if l1 > l2
1320 }
1321 }
1322
1323 return 0;
1324 }
1325
1326
1327 /*
1328 * Test whether c precedes d in the order (strictly)
1329 */
app_lt(egraph_t * egraph,composite_t * c,composite_t * d)1330 static bool app_lt(egraph_t *egraph, composite_t *c, composite_t *d) {
1331 return app_cmp(egraph, c, d) < 0;
1332 }
1333
1334
1335 /*
1336 * Sort vector v of composites and remove equivalent elements
1337 * - v must be non NULL
1338 */
normalize_app_vector(fun_solver_t * solver,void ** v)1339 static void normalize_app_vector(fun_solver_t *solver, void **v) {
1340 egraph_t *egraph;
1341 uint32_t i, j, n;
1342 composite_t *c, *d;
1343
1344 assert(v != NULL);
1345
1346 egraph = solver->egraph;
1347 n = pv_size(v);
1348
1349 if (n > 0) {
1350 ptr_array_sort2(v, n, egraph, (ptr_cmp_fun_t) app_lt);
1351
1352 // remove duplicates
1353 c = v[0];
1354 j = 1;
1355 for (i=1; i<n; i++) {
1356 d = v[i];
1357 if (! app_equiv(egraph, c, d)) {
1358 v[j] = d;
1359 c = d;
1360 j ++;
1361 } else {
1362 assert(egraph_equal_terms(egraph, c->id, d->id));
1363 }
1364 }
1365
1366 // update size of v
1367 ptr_vector_shrink(v, j);
1368 }
1369 }
1370
1371
1372
1373 /*
1374 * Normalize the app vectors of all the roots
1375 * - set apps_ready flag to true
1376 */
fun_solver_normalize_apps(fun_solver_t * solver)1377 static void fun_solver_normalize_apps(fun_solver_t *solver) {
1378 fun_vartable_t *vtbl;
1379 uint32_t i, n;
1380
1381 vtbl = &solver->vtbl;
1382 n = vtbl->nvars;
1383 for (i=0; i<n; i++) {
1384 if (vtbl->root[i] == i && vtbl->app[i] != NULL) {
1385 normalize_app_vector(solver, vtbl->app[i]);
1386 }
1387 }
1388
1389 solver->apps_ready = true;
1390 }
1391
1392
1393
1394
1395
1396 /********************************************
1397 * PROPAGATION/CHECK FOR UPDATE CONFLICTS *
1398 *******************************************/
1399
1400 /*
1401 * If x is a root variable and c = (apply f i_1 ... i_n) is a composite with class[f] == x
1402 * then we propagate that (apply z i_1 ... i_n) must be equal to (apply f i_1 ... i_n) for
1403 * all nodes z connected to x via a path that does not mask i_1 ... i_n.
1404 *
1405 * A path masks i_1 ... i_n, if it contains an edge labelled by [j_1 ... j_n] and
1406 * j_1 == i_1, ..., j_n == i_n holds in the egraph.
1407 *
1408 * There's a conflict if there's a composite d congruent to (apply z
1409 * i_1 ... i_n) that's in a different equivalence class than c in
1410 * the egraph.
1411 *
1412 * If a conflict is found, we add instances of axiom2 to the core.
1413 * Otherwise, we add c to app[root[z]] for all z found along the way.
1414 */
1415
1416
1417 /*
1418 * Check whether edge i is masking for application c
1419 */
masking_edge(fun_solver_t * solver,int32_t i,composite_t * c)1420 static bool masking_edge(fun_solver_t *solver, int32_t i, composite_t *c) {
1421 egraph_t *egraph;
1422 fun_edge_t *e;
1423 uint32_t n, j;
1424
1425 assert(composite_kind(c) == COMPOSITE_APPLY && composite_arity(c) > 0);
1426
1427 egraph = solver->egraph;
1428 e = get_edge(&solver->etbl, i);
1429 n = composite_arity(c) - 1;
1430
1431 assert(solver->vtbl.arity[e->source] == n);
1432
1433 for (j=0; j<n; j++) {
1434 if (! egraph_equal_occ(egraph, e->index[j], composite_child(c, j+1))) {
1435 return false;
1436 }
1437 }
1438 return true;
1439 }
1440
1441
1442 /*
1443 * Check whether c = (apply f i_1 ... i_n) and d = (apply g j_1 ... j_n)
1444 * are equal in the egraph
1445 */
egraph_equal_apps(egraph_t * egraph,composite_t * c,composite_t * d)1446 static inline bool egraph_equal_apps(egraph_t *egraph, composite_t *c, composite_t *d) {
1447 assert(c->tag == d->tag && composite_kind(c) == COMPOSITE_APPLY);
1448 return egraph_equal_terms(egraph, c->id, d->id);
1449 }
1450
1451
1452 /*
1453 * Negate all literals in vector v
1454 */
negate_vector(ivector_t * v)1455 static void negate_vector(ivector_t *v) {
1456 uint32_t i, n;
1457
1458 n = v->size;
1459 for (i=0; i<n; i++) {
1460 v->data[i] = not(v->data[i]);
1461 }
1462 }
1463
1464
1465 #if TRACE
1466 /*
1467 * For debugging/trace: return the length of the path from x to z
1468 */
path_length(fun_solver_t * solver,thvar_t x,thvar_t z)1469 static uint32_t path_length(fun_solver_t *solver, thvar_t x, thvar_t z) {
1470 fun_vartable_t *vtbl;
1471 int32_t i;
1472 thvar_t y;
1473 uint32_t n;
1474
1475 vtbl = &solver->vtbl;
1476
1477 n = 0;
1478 y = z;
1479 do {
1480 n ++;
1481 i = vtbl->pre[y];
1482 y = previous_root(solver, y, i);
1483 } while (y != x);
1484
1485 return n;
1486 }
1487
1488 #endif
1489
1490
1491 /*
1492 * Add instance of the update2 axiom corresponding to the non-masking
1493 * path from x to z encoded in the vtbl->pre fields.
1494 * - x = source node
1495 * - z = end node
1496 * - c = composite of the form (apply f i_1 ... i_n) with f in class of x
1497 * - d = composite of the from (apply g j_1 ... j_n) with g in class of z
1498 * - c and d are in distinct classes in the egraph
1499 * - i_1 == j_1 .... i_n == j_n hold in the egraph
1500 * Since there's path from x to z and the path is non-masking, we should
1501 * have c == d. We add the axiom that states this.
1502 */
fun_solver_add_axiom2(fun_solver_t * solver,thvar_t x,thvar_t z,composite_t * c,composite_t * d)1503 static void fun_solver_add_axiom2(fun_solver_t *solver, thvar_t x, thvar_t z, composite_t *c, composite_t *d) {
1504 ivector_t *lemma;
1505 fun_vartable_t *vtbl;
1506 thvar_t y;
1507 int32_t i;
1508 literal_t l;
1509
1510 vtbl = &solver->vtbl;
1511
1512 #if TRACE
1513 printf("\n--- Update conflict ---\n");
1514 #if 0
1515 printf("Classes:\n");
1516 print_fsolver_classes(stdout, solver);
1517 printf("Disequalities:\n");
1518 print_fsolver_diseqs(stdout, solver);
1519 printf("Applications:\n");
1520 print_fsolver_apps(stdout, solver);
1521 printf("\n\n");
1522 #endif
1523
1524 printf("Source var: f!%"PRId32", ", x);
1525 print_eterm_def(stdout, solver->egraph, fun_solver_eterm_of_var(solver, x));
1526 printf("Target var: f!%"PRId32", ", z);
1527 print_eterm_def(stdout, solver->egraph, fun_solver_eterm_of_var(solver, z));
1528 printf("Source app: ");
1529 print_eterm_def(stdout, solver->egraph, c->id);
1530 printf("Target app: ");
1531 print_eterm_def(stdout, solver->egraph, d->id);
1532 printf("Path length: %"PRIu32"\n", path_length(solver, x, z));
1533
1534 #if 0
1535 printf("Path:\n");
1536 y = z;
1537 do {
1538 i = vtbl->pre[y];
1539 assert(i >= 0 && i != null_fun_pred);
1540 print_fsolver_edge(stdout, solver, i);
1541 printf("\n");
1542 y = previous_root(solver, y, i);
1543 } while (y != x);
1544 #endif
1545
1546 fflush(stdout);
1547
1548 #endif
1549
1550 /*
1551 * Create the lemma
1552 */
1553 lemma = &solver->lemma_vector;
1554 assert(lemma->size == 0);
1555 // collect the path atoms + equal args atom
1556 collect_path_atoms(solver, x, z, c, d, lemma);
1557 collect_equal_arg_atoms(solver, c, d, lemma);
1558
1559 #if TRACE
1560 printf("\n--- Update lemma ---\n");
1561 #endif
1562
1563 if (lemma->size > 0) {
1564 #if TRACE
1565 printf("path constraints:\n");
1566 if (lemma->size == 1) {
1567 print_egraph_atom_of_literal(stdout, solver->egraph, lemma->data[0]);
1568 } else {
1569 printf("(AND");
1570 for (i=0; i<lemma->size; i++) {
1571 printf(" ");
1572 print_egraph_atom_of_literal(stdout, solver->egraph, lemma->data[i]);
1573 }
1574 printf(")");
1575 }
1576 printf("\n");
1577 #endif
1578
1579 negate_vector(lemma);
1580 }
1581
1582 // add the edge constraints
1583 y = z;
1584 do {
1585 i = vtbl->pre[y];
1586 assert(i >= 0 && i != null_fun_pred);
1587 l = apply_edge_equal_args(solver, c, get_edge(&solver->etbl, i));
1588 // l = apply_edge_equal_args(solver, d, get_edge(&solver->etbl, i));
1589 if (l != false_literal) {
1590 ivector_push(lemma, l);
1591 }
1592 y = previous_root(solver, y, i);
1593 } while (y != x);
1594
1595
1596 // add the consequent: (c == d)
1597 l = equal_applies(solver, c, d);
1598 ivector_push(lemma, l);
1599
1600 #if TRACE
1601 if (lemma->size > 1) {
1602 printf("antecedents:\n");
1603 for (i=0; i<lemma->size - 1; i++) {
1604 print_literal(stdout, lemma->data[i]);
1605 printf(" := ");
1606 print_egraph_atom_of_literal(stdout, solver->egraph, lemma->data[i]);
1607 printf("\n");
1608 }
1609 }
1610 printf("consequent:\n");
1611 print_literal(stdout, l);
1612 printf(" := ");
1613 print_egraph_atom_of_literal(stdout, solver->egraph, l);
1614 printf("\n\n");
1615 #endif
1616
1617 add_clause(solver->core, lemma->size, lemma->data);
1618
1619 #if TRACE
1620 printf("clause:\n (OR");
1621 for (i=0; i<lemma->size; i++) {
1622 printf(" ");
1623 print_literal(stdout, lemma->data[i]);
1624 }
1625 printf(")\n\n");
1626 fflush(stdout);
1627 #endif
1628
1629 ivector_reset(lemma);
1630
1631 solver->stats.num_update_axiom2 ++;
1632 }
1633
1634
1635 /*
1636 * Propagate c = (apply f i_1 ... i_n) to all root variables z reachable from
1637 * x via a non-masking path and check for conflict. A conflict is found if
1638 * there's d = (apply g j_1 ... j_n) such that
1639 * 1) g is in the class of a variable z, reachable from x via a non-masking path
1640 * 2) j_1 ... j_n are equal to i_1 ... i_n in the egraph.
1641 *
1642 * Input:
1643 * - x must be a root variable
1644 * - c = (apply f ...) where f belongs to the class of x
1645 *
1646 * Result:
1647 * - return true if there's a conflict, false otherwise
1648 * - if there's no conflict, c is added to vtbl->app[z] for all root variables z
1649 * - if there's a conflict, c may be added to vtbl->app[z] for some z's
1650 * - if a conflict is found, then an instance of the generalized update axiom 2
1651 * is added to the core.
1652 */
update_conflict_for_application(fun_solver_t * solver,thvar_t x,composite_t * c)1653 static bool update_conflict_for_application(fun_solver_t *solver, thvar_t x, composite_t *c) {
1654 fun_queue_t *queue;
1655 egraph_t *egraph;
1656 fun_vartable_t *vtbl;
1657 composite_t *d;
1658 int32_t *edges;
1659 thvar_t y, z;
1660 uint32_t n, i;
1661 int32_t k;
1662 bool result;
1663
1664 egraph = solver->egraph;
1665 vtbl = &solver->vtbl;
1666 assert(vtbl->root[x] == x);
1667 queue = &solver->queue;
1668 assert(queue->top == 0 && queue->ptr == 0);
1669
1670
1671 fun_queue_push(queue, x);
1672 // mark that x is the source
1673 vtbl->pre[x] = null_fun_pred;
1674
1675 while (! empty_fun_queue(queue)) {
1676 z = fun_queue_pop(queue);
1677 assert(vtbl->root[z] == z);
1678
1679 /*
1680 * Check for conflicts
1681 */
1682 d = egraph_find_modified_application(egraph, vtbl->eterm[z], c);
1683 if (z != x && d != NULL_COMPOSITE) {
1684 if (! egraph_equal_apps(egraph, c, d)) {
1685 // conflict: add an instance of the update axiom
1686 fun_solver_add_axiom2(solver, x, z, c, d);
1687 result = true;
1688 goto done;
1689 }
1690 } else {
1691 /*
1692 * No conflict and no matching composite in z's class
1693 * - add c to app[z]
1694 * - explore the neighbors of all nodes in the class of z
1695 */
1696 add_ptr_to_vector(vtbl->app + z, c); // We could do this only after checking for conflicts
1697 do {
1698 // edges incident to node z
1699 edges = vtbl->edges[z];
1700 if (edges != NULL) {
1701 n = iv_size(edges);
1702 for (i=0; i<n; i++) {
1703 k = edges[i];
1704 y = adjacent_root(solver, z, k);
1705 if (vtbl->pre[y] < 0 && !masking_edge(solver, k, c)) {
1706 // y not visited yet: add it to the queue
1707 fun_queue_push(queue, y);
1708 vtbl->pre[y] = k;
1709 }
1710 }
1711 }
1712 z = vtbl->next[z];
1713 } while (z != null_thvar);
1714 }
1715 }
1716
1717 result = false;
1718
1719 done:
1720 // reset pre[y] to null for all y in the queue
1721 n = queue->top;
1722 for (i=0; i<n; i++) {
1723 y = queue->data[i];
1724 assert(vtbl->pre[y] >= 0);
1725 vtbl->pre[y] = null_fun_edge;
1726 }
1727 reset_fun_queue(queue);
1728
1729 return result;
1730 }
1731
1732
1733 /*
1734 * Get the root variable for f in c = (apply f ....)
1735 */
root_app_var(egraph_t * egraph,composite_t * c)1736 static thvar_t root_app_var(egraph_t *egraph, composite_t *c) {
1737 eterm_t f;
1738
1739 assert(composite_kind(c) == COMPOSITE_APPLY);
1740 f = term_of_occ(c->child[0]);
1741 return egraph_class_thvar(egraph, egraph_term_class(egraph, f));
1742 }
1743
1744
1745 /*
1746 * Collect all applications and check for update conflicts
1747 * - the equivalence classes and roots must be set first
1748 * - return true if no conflict is found, false otherwise
1749 */
update_conflicts(fun_solver_t * solver)1750 static bool update_conflicts(fun_solver_t *solver) {
1751 egraph_t *egraph;
1752 ppart_t *pp;
1753 void **v;
1754 composite_t *c;
1755 uint32_t i, j, n, m;
1756 thvar_t x;
1757 bool result;
1758 uint32_t num_updates;
1759
1760 assert(solver->vtbl.nvars > 0);
1761
1762 // build the classes of relevant composites in the egraph
1763 egraph = solver->egraph;
1764 egraph_build_arg_partition(egraph);
1765
1766 // limit: one conflict per class
1767 result = false;
1768 num_updates = 0;
1769
1770 // get the partition and process all composites that
1771 // are in a non-singleton class
1772 pp = egraph_app_partition(egraph);
1773 n = ptr_partition_nclasses(pp);
1774 for (i=0; i<n; i++) {
1775 v = pp->classes[i];
1776 m = ppv_size(v);
1777 assert(m >= 2);
1778 for (j=0; j<m; j++) {
1779 c = v[j];
1780 x = root_app_var(egraph, c);
1781 if (update_conflict_for_application(solver, x, c)) {
1782 result = true;
1783 num_updates ++;
1784 // exit if max_update_conflicts is reached
1785 // move to the next class otherwise
1786 if (num_updates >= solver->max_update_conflicts) goto done;
1787 break;
1788 }
1789 }
1790 }
1791
1792
1793 #if 0
1794 // EXPERIMENT
1795 pp = egraph_app_partition(egraph);
1796 n = egraph->terms.nterms;
1797 for (i=0; i<n; i++) {
1798 c = egraph_term_body(egraph, i);
1799 if (composite_body(c) &&
1800 composite_kind(c) == COMPOSITE_APPLY &&
1801 congruence_table_is_root(&egraph->ctable, c, egraph->terms.label) &&
1802 ptr_partition_get_index(pp, c) >= 0) {
1803 x = root_app_var(egraph, c);
1804 if (update_conflict_for_application(solver, x, c)) {
1805 result = true;
1806 num_updates ++;
1807 // exit if max_update_conflicts is reached
1808 if (num_updates >= solver->max_update_conflicts) goto done;
1809 }
1810 }
1811 }
1812 #endif
1813
1814
1815 done:
1816 if (num_updates > 0) {
1817 if (num_updates == 1) {
1818 trace_printf(solver->core->trace, 5, "(array solver: 1 update lemma)\n");
1819 } else {
1820 trace_printf(solver->core->trace, 5, "(array solver: %"PRIu32" update lemmas)\n", num_updates);
1821 }
1822 #if TRACE
1823 printf("---> ARRAY SOLVER: update axioms in %"PRIu32" classes out of %"PRIu32"\n", num_updates, n);
1824 #endif
1825 }
1826
1827 // cleanup
1828 egraph_reset_app_partition(egraph);
1829
1830 return result;
1831 }
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841 /*****************
1842 * FULL SOLVER *
1843 ****************/
1844
1845 /*
1846 * Initialization
1847 * - core = attached smt_core
1848 * - gates = gate manager for the core
1849 * - egraph = attached egraph
1850 * - ttbl = attached type table
1851 */
init_fun_solver(fun_solver_t * solver,smt_core_t * core,gate_manager_t * gates,egraph_t * egraph,type_table_t * ttbl)1852 void init_fun_solver(fun_solver_t *solver, smt_core_t *core,
1853 gate_manager_t *gates, egraph_t *egraph, type_table_t *ttbl) {
1854
1855 solver->core = core;
1856 solver->gate_manager = gates;
1857 solver->egraph = egraph;
1858 solver->types = ttbl;
1859
1860 solver->base_level = 0;
1861 solver->decision_level = 0;
1862
1863 init_fun_solver_statistics(&solver->stats);
1864
1865 solver->max_update_conflicts = DEFAULT_MAX_UPDATE_CONFLICTS;
1866 solver->max_extensionality = DEFAULT_MAX_EXTENSIONALITY;
1867
1868 init_fun_vartable(&solver->vtbl);
1869 init_edge_table(&solver->etbl);
1870 init_fun_queue(&solver->queue);
1871 init_diseq_stack(&solver->dstack);
1872 init_fun_trail_stack(&solver->trail_stack);
1873
1874 init_ivector(&solver->aux_vector, 10);
1875 init_ivector(&solver->lemma_vector, 10);
1876 init_pvector(&solver->app_vector, 10);
1877
1878 solver->apps_ready = false;
1879 solver->bases_ready = false;
1880 solver->reconciled = false;
1881
1882 solver->num_bases = 0;
1883 solver->base_value = NULL;
1884
1885 solver->value = NULL;
1886 solver->base_map = NULL;
1887 solver->value_size = 0;
1888 solver->base_map_size = 0;
1889 solver->fresh_hmap = NULL;
1890 }
1891
1892
1893 /*
1894 * Delete the solver
1895 */
delete_fun_solver(fun_solver_t * solver)1896 void delete_fun_solver(fun_solver_t *solver) {
1897 delete_fun_vartable(&solver->vtbl);
1898 delete_edge_table(&solver->etbl);
1899 delete_fun_queue(&solver->queue);
1900 delete_diseq_stack(&solver->dstack);
1901 delete_fun_trail_stack(&solver->trail_stack);
1902
1903 delete_ivector(&solver->aux_vector);
1904 delete_ivector(&solver->lemma_vector);
1905 delete_pvector(&solver->app_vector);
1906
1907 if (solver->value != NULL) {
1908 fun_solver_delete_values(solver);
1909 assert(solver->value == NULL);
1910 }
1911
1912 if (solver->base_value != NULL) {
1913 safe_free(solver->base_value);
1914 solver->base_value = NULL;
1915 }
1916
1917 if (solver->base_map != NULL) {
1918 fun_solver_delete_base_maps(solver);
1919 assert(solver->base_map == NULL);
1920 }
1921
1922 fun_solver_delete_fresh_hmap(solver);
1923 }
1924
1925
1926 /*
1927 * Reset
1928 */
fun_solver_reset(fun_solver_t * solver)1929 void fun_solver_reset(fun_solver_t *solver) {
1930 solver->base_level = 0;
1931 solver->decision_level = 0;
1932 reset_fun_solver_statistics(&solver->stats);
1933 reset_fun_vartable(&solver->vtbl);
1934 reset_edge_table(&solver->etbl);
1935 reset_fun_queue(&solver->queue);
1936 reset_diseq_stack(&solver->dstack);
1937 reset_fun_trail_stack(&solver->trail_stack);
1938
1939 ivector_reset(&solver->aux_vector);
1940 ivector_reset(&solver->lemma_vector);
1941 pvector_reset(&solver->app_vector);
1942
1943 solver->apps_ready = false;
1944 solver->bases_ready = false;
1945 solver->reconciled = false;
1946
1947 solver->num_bases = 0;
1948 if (solver->value != NULL) {
1949 fun_solver_delete_values(solver);
1950 assert(solver->value == NULL);
1951 }
1952
1953 if (solver->base_map != NULL) {
1954 fun_solver_delete_base_maps(solver);
1955 assert(solver->base_map == NULL);
1956 }
1957
1958 if (solver->base_value != NULL) {
1959 safe_free(solver->base_value);
1960 solver->base_value = NULL;
1961 }
1962
1963 fun_solver_delete_fresh_hmap(solver);
1964 }
1965
1966
1967
1968 /*
1969 * Increase the decision level
1970 */
fun_solver_increase_decision_level(fun_solver_t * solver)1971 void fun_solver_increase_decision_level(fun_solver_t *solver) {
1972 uint32_t k;
1973
1974 k = solver->decision_level + 1;
1975 solver->decision_level = k;
1976 diseq_stack_increase_dlevel(&solver->dstack, k);
1977 }
1978
1979
1980 /*
1981 * Backtrack to back_level:
1982 * - remove disequalities asserted at levels back_level + 1, ...
1983 */
fun_solver_backtrack(fun_solver_t * solver,uint32_t back_level)1984 void fun_solver_backtrack(fun_solver_t *solver, uint32_t back_level) {
1985 assert(solver->base_level <= back_level && back_level < solver->decision_level);
1986 diseq_stack_backtrack(&solver->dstack, back_level);
1987 solver->decision_level = back_level;
1988 }
1989
1990
1991 /*
1992 * Push:
1993 * - save number of variables & edges
1994 * - increase base level & decision level
1995 */
fun_solver_push(fun_solver_t * solver)1996 void fun_solver_push(fun_solver_t *solver) {
1997 assert(solver->base_level == solver->decision_level);
1998
1999 fun_trail_stack_save(&solver->trail_stack, solver->vtbl.nvars, solver->etbl.nedges);
2000 solver->base_level ++;
2001 fun_solver_increase_decision_level(solver);
2002 assert(solver->base_level == solver->decision_level);
2003 }
2004
2005
2006 /*
2007 * Pop:
2008 * - remove variables & edges added at the current base level
2009 * - decrement base level and decision level
2010 */
fun_solver_pop(fun_solver_t * solver)2011 void fun_solver_pop(fun_solver_t *solver) {
2012 fun_trail_t *top;
2013 fun_vartable_t *vtbl;
2014 fun_edgetable_t *etbl;
2015 fun_edge_t *e;
2016 uint32_t i, n;
2017 thvar_t x;
2018
2019 assert(solver->base_level > 0 && solver->base_level == solver->decision_level);
2020 top = fun_trail_stack_top(&solver->trail_stack);
2021 vtbl = &solver->vtbl;
2022 etbl = &solver->etbl;
2023
2024 // remove edges from vtbl->edges
2025 i = etbl->nedges;
2026 n = top->nvars;
2027 while (i > top->nedges) {
2028 i --;
2029 e = etbl->data[i];
2030 x = e->source;
2031 if (x < n) {
2032 remove_index_from_vector(vtbl->edges[x], i);
2033 }
2034 x = e->target;
2035 if (x < n) {
2036 remove_index_from_vector(vtbl->edges[x], i);
2037 }
2038 }
2039
2040 // remove edges and variables
2041 shrink_fun_vartable(&solver->vtbl, top->nvars);
2042 shrink_edge_table(&solver->etbl, top->nedges);
2043
2044 solver->base_level --;
2045 fun_trail_stack_pop(&solver->trail_stack);
2046
2047 fun_solver_backtrack(solver, solver->base_level);
2048 }
2049
2050
2051 /*
2052 * Prepare for internalization: do nothing
2053 */
fun_solver_start_internalization(fun_solver_t * solver)2054 void fun_solver_start_internalization(fun_solver_t *solver) {
2055 }
2056
2057 /*
2058 * Start search
2059 */
fun_solver_start_search(fun_solver_t * solver)2060 void fun_solver_start_search(fun_solver_t *solver) {
2061 solver->stats.num_init_vars = solver->vtbl.nvars;
2062 solver->stats.num_init_edges = solver->etbl.nedges;
2063 solver->reconciled = false;
2064
2065 #if TRACE
2066 printf("\n=== START SEARCH ===\n");
2067 print_fsolver_vars(stdout, solver);
2068 printf("\n");
2069 print_fsolver_edges(stdout, solver);
2070 printf("\n\n");
2071 #endif
2072 }
2073
2074
2075 /*
2076 * Propagate: do nothing
2077 * - all the work is done in final_check
2078 */
fun_solver_propagate(fun_solver_t * solver)2079 bool fun_solver_propagate(fun_solver_t *solver) {
2080 return true;
2081 }
2082
2083
2084
2085 /*
2086 * FINAL CHECK: deal only with update conflicts.
2087 * Extensionality is handled in reconcile_model.
2088 *
2089 * Search for update conflicts. If a conflict if found,
2090 * add an instance of Axiom 2 to get rid of it
2091 * - return FCHECK_CONTINUE if an instance is generated
2092 * - return FCHCEK_SAT otherwise (i.e., no update conflict was found)
2093 */
fun_solver_final_check(fun_solver_t * solver)2094 fcheck_code_t fun_solver_final_check(fun_solver_t *solver) {
2095 fcheck_code_t result;
2096
2097 #if TRACE
2098 printf("\n**** FUNSOLVER: FINAL CHECK ***\n\n");
2099 #endif
2100
2101 #if TRACE
2102 print_egraph_terms(stdout, solver->egraph);
2103 printf("\n\n");
2104 print_egraph_root_classes_details(stdout, solver->egraph);
2105 #endif
2106
2107 if (solver->etbl.nedges == 0) {
2108 // nothing to do
2109 return FCHECK_SAT;
2110 }
2111
2112 // check for update conflicts
2113 result = FCHECK_SAT;
2114 fun_solver_build_classes(solver);
2115 if (update_conflicts(solver)) {
2116 #if TRACE
2117 printf("---> FUN Solver: update conflict\n");
2118 #endif
2119 result = FCHECK_CONTINUE;
2120 }
2121
2122 // cleanup and return
2123 fun_solver_cleanup(solver);
2124 return result;
2125 }
2126
2127
2128 /*
2129 * Clear: nothing to do
2130 */
fun_solver_clear(fun_solver_t * solver)2131 void fun_solver_clear(fun_solver_t *solver) {
2132 }
2133
2134
2135
2136 /***********************
2137 * INTERNALIZATION *
2138 **********************/
2139
2140 /*
2141 * Create a fresh array variable x of type tau
2142 * - type[x] and arity[x] are set
2143 * - fdom[x] = 1 if tau has finite domain or 0 otherwise
2144 * - eterm[x] = null_eterm
2145 * - edges[x] = NULL
2146 *
2147 * - pre[x] = null_edge
2148 * - app[x] = NULL
2149 * - base[x] = -1;
2150 * - mark[x] = 0
2151 * - root[x] and next[x] are not initialized
2152 */
fun_solver_create_var(fun_solver_t * solver,type_t tau)2153 thvar_t fun_solver_create_var(fun_solver_t *solver, type_t tau) {
2154 fun_vartable_t *vtbl;
2155 thvar_t x;
2156
2157 assert(good_type(solver->types, tau) && type_kind(solver->types, tau) == FUNCTION_TYPE);
2158 vtbl = &solver->vtbl;
2159 x = fun_vartable_alloc(vtbl);
2160 vtbl->type[x] = tau;
2161 vtbl->arity[x] = function_type_arity(solver->types, tau);
2162 assign_bit(vtbl->fdom, x, type_has_finite_domain(solver->types, tau));
2163 vtbl->eterm[x] = null_eterm;
2164 vtbl->edges[x] = NULL;
2165
2166 vtbl->pre[x] = null_fun_edge;
2167 vtbl->base[x] = -1;
2168 vtbl->app[x] = NULL;
2169 clr_bit(vtbl->mark, x);
2170
2171 return x;
2172 }
2173
2174
2175
2176 /*
2177 * Create a new edge
2178 * - x = source var
2179 * - y = target var
2180 * - u = update composite
2181 */
fun_solver_add_edge(fun_solver_t * solver,thvar_t x,thvar_t y,composite_t * u)2182 static void fun_solver_add_edge(fun_solver_t *solver, thvar_t x, thvar_t y, composite_t *u) {
2183 fun_edgetable_t *etbl;
2184 fun_vartable_t *vtbl;
2185 fun_edge_t *e;
2186 int32_t i;
2187
2188 etbl = &solver->etbl;
2189 vtbl = &solver->vtbl;
2190
2191 e = make_edge(x, y, u);
2192 i = edge_table_alloc(etbl);
2193 etbl->data[i] = e;
2194 add_index_to_vector(vtbl->edges + x, i);
2195 add_index_to_vector(vtbl->edges + y, i);
2196 }
2197
2198
2199 /*
2200 * Attach eterm t to variable x
2201 * - if t is an update term, add an edge and instantiate axiom1
2202 */
fun_solver_attach_eterm(fun_solver_t * solver,thvar_t x,eterm_t t)2203 void fun_solver_attach_eterm(fun_solver_t *solver, thvar_t x, eterm_t t) {
2204 egraph_t *egraph;
2205 composite_t *cmp;
2206 occ_t f;
2207 thvar_t y;
2208
2209 assert(0 <= x && x < solver->vtbl.nvars && solver->vtbl.eterm[x] == null_eterm);
2210
2211 solver->vtbl.eterm[x] = t;
2212
2213 egraph = solver->egraph;
2214 cmp = egraph_term_body(egraph, t);
2215 if (composite_body(cmp) && composite_kind(cmp) == COMPOSITE_UPDATE) {
2216 // t is (update f i_1 ... i_n v)
2217 f = composite_child(cmp, 0);
2218 y = egraph_term_base_thvar(egraph, term_of_occ(f));
2219 assert(0 <= y && y < solver->vtbl.nvars && solver->vtbl.eterm[y] == term_of_occ(f));
2220 // create the edge y ---> x
2221 fun_solver_add_edge(solver, y, x, cmp);
2222
2223 // add the axiom ((update f i_1 ... i_n v) i_1 ... i_n) = v
2224 fun_solver_update_axiom1(solver, t, cmp, solver->vtbl.type[x]);
2225
2226 // NOTE: adding the axiom may create a new array variable and recursively
2227 // call attach_eterm. This should be safe as the new term can't be an update.
2228 }
2229 }
2230
2231
2232 /*
2233 * Return the eterm attached to theory variable x
2234 * TODO: clean this up. No need to duplicate this?
2235 */
fun_solver_get_eterm_of_var(fun_solver_t * solver,thvar_t x)2236 eterm_t fun_solver_get_eterm_of_var(fun_solver_t *solver, thvar_t x) {
2237 return fun_solver_eterm_of_var(solver, x);
2238 }
2239
2240
2241
2242
2243
2244 /***********************
2245 * EGRAPH INTERFACE *
2246 **********************/
2247
2248 /*
2249 * Assert that x1 and x2 are equal: do nothing
2250 */
fun_solver_assert_var_eq(fun_solver_t * solver,thvar_t x1,thvar_t x2,int32_t id)2251 void fun_solver_assert_var_eq(fun_solver_t *solver, thvar_t x1, thvar_t x2, int32_t id) {
2252 assert(0 <= x1 && x1 < solver->vtbl.nvars && 0 <= x2 && x2 < solver->vtbl.nvars);
2253 }
2254
2255
2256 /*
2257 * Assert that x1 and x2 are distinct: push the disequality onto the diseq stack
2258 */
fun_solver_assert_var_diseq(fun_solver_t * solver,thvar_t x1,thvar_t x2,composite_t * hint)2259 void fun_solver_assert_var_diseq(fun_solver_t *solver, thvar_t x1, thvar_t x2, composite_t *hint) {
2260 assert(0 <= x1 && x1 < solver->vtbl.nvars && 0 <= x2 && x2 < solver->vtbl.nvars);
2261 diseq_stack_push(&solver->dstack, x1, x2);
2262 }
2263
2264
2265 /*
2266 * Assert that all variables a[0] ... a[n-1] are pairwise distinct
2267 * - they are attached to egraph terms t[0] ... t[n-1]
2268 * - the function is called when (distinct t[0] ... t[n-1]) is asserted in the egraph
2269 */
fun_solver_assert_var_distinct(fun_solver_t * solver,uint32_t n,thvar_t * a,composite_t * hint)2270 void fun_solver_assert_var_distinct(fun_solver_t *solver, uint32_t n, thvar_t *a, composite_t *hint) {
2271 thvar_t x, y;
2272 uint32_t i, j;
2273
2274 for (i=0; i<n; i++) {
2275 x = a[i];
2276 assert(0 <= x && x < solver->vtbl.nvars);
2277 for (j=i+1; j<n; j++) {
2278 y = a[j];
2279 diseq_stack_push(&solver->dstack, x, y);
2280 }
2281 }
2282 }
2283
2284
2285
2286 /*
2287 * Check whether x1 and x2 are distinct at the base level
2288 * - do nothing for now. Always return false.
2289 */
fun_solver_check_disequality(fun_solver_t * solver,thvar_t x1,thvar_t x2)2290 bool fun_solver_check_disequality(fun_solver_t *solver, thvar_t x1, thvar_t x2) {
2291 assert(0 <= x1 && x1 < solver->vtbl.nvars && 0 <= x2 && x2 < solver->vtbl.nvars);
2292 return false;
2293 }
2294
2295
2296 /*
2297 * Check whether x is a constant
2298 */
fun_solver_var_is_constant(fun_solver_t * solver,thvar_t x)2299 bool fun_solver_var_is_constant(fun_solver_t *solver, thvar_t x) {
2300 return false;
2301 }
2302
2303
2304 /*
2305 * Select whether to branch on (x1 == x2) or (x1 != x2)
2306 * - always return (not l): branch on (x1 != x2)
2307 */
fun_solver_select_eq_polarity(fun_solver_t * solver,thvar_t x1,thvar_t x2,literal_t l)2308 literal_t fun_solver_select_eq_polarity(fun_solver_t *solver, thvar_t x1, thvar_t x2, literal_t l) {
2309 return not(l);
2310 }
2311
2312
2313 /*
2314 * INTERFACE EQUALITIES
2315 */
2316
2317
2318 /*
2319 * Propagate c = (apply f i_1 ... i_n) to all root variables z reachable
2320 * from x = root variable for f via a non-masking path.
2321 */
propagate_application(fun_solver_t * solver,composite_t * c,thvar_t x)2322 static void propagate_application(fun_solver_t *solver, composite_t *c, thvar_t x) {
2323 fun_queue_t *queue;
2324 fun_vartable_t *vtbl;
2325 #ifndef NDEBUG
2326 egraph_t *egraph;
2327 composite_t *d;
2328 #endif
2329 int32_t *edges;
2330 thvar_t y, z;
2331 uint32_t n, i;
2332 int32_t k;
2333
2334 vtbl = &solver->vtbl;
2335 queue = &solver->queue;
2336 assert(queue->top == 0 && queue->ptr == 0);
2337
2338 assert(vtbl->root[x] == x);
2339 fun_queue_push(queue, x);
2340 set_bit(vtbl->mark, x);
2341
2342 while (! empty_fun_queue(queue)) {
2343 z = fun_queue_pop(queue);
2344 assert(vtbl->root[z] == z && tst_bit(vtbl->mark, z));
2345
2346 #ifndef NDEBUG
2347 // there should be no update conflict when this function is called
2348 egraph = solver->egraph;
2349 d = egraph_find_modified_application(egraph, vtbl->eterm[z], c);
2350 assert(d == NULL_COMPOSITE || egraph_equal_apps(egraph, c, d));
2351 #endif
2352
2353 /*
2354 * Add c to z's app vector
2355 * - explore the neighbors of all nodes in z's class
2356 */
2357 add_ptr_to_vector(vtbl->app + z, c);
2358 do {
2359 edges = vtbl->edges[z]; // edges incident to z
2360 if (edges != NULL) {
2361 n = iv_size(edges);
2362 for (i=0; i<n; i++) {
2363 k = edges[i];
2364 y = adjacent_root(solver, z, k);
2365 if (!tst_bit(vtbl->mark, y) && !masking_edge(solver, k, c)) {
2366 // y not visited yet and reached via a non-masking path
2367 fun_queue_push(queue, y);
2368 set_bit(vtbl->mark, y);
2369 }
2370 }
2371 }
2372 z = vtbl->next[z]; // next node in the class
2373 } while (z != null_thvar);
2374 }
2375
2376 // clear the marks of all nodes in the queue
2377 n = queue->top;
2378 for (i=0; i<n; i++) {
2379 y = queue->data[i];
2380 assert(tst_bit(vtbl->mark, y));
2381 clr_bit(vtbl->mark, y);
2382 }
2383
2384 reset_fun_queue(queue);
2385 }
2386
2387
2388 /*
2389 * Add all applications in vector v
2390 * - x = corresponding root variable.
2391 * - all composites in v must be of the form (apply f ....) where f
2392 * is in the same egraph class as x's eterm.
2393 */
build_apps_from_var(fun_solver_t * solver,thvar_t x,pvector_t * v)2394 static void build_apps_from_var(fun_solver_t *solver, thvar_t x, pvector_t *v) {
2395 uint32_t i, n;
2396
2397 n = v->size;
2398 for (i=0; i<n; i++) {
2399 propagate_application(solver, v->data[i], x);
2400 }
2401 }
2402
2403
2404 /*
2405 * Build the full app vector for each root variable
2406 */
fun_solver_build_apps(fun_solver_t * solver)2407 static void fun_solver_build_apps(fun_solver_t *solver) {
2408 fun_vartable_t *vtbl;
2409 pvector_t v;
2410 uint32_t i, n;
2411 thvar_t x;
2412
2413 assert(solver->vtbl.nvars > 0);
2414
2415 init_pvector(&v, 50);
2416 vtbl = &solver->vtbl;
2417 n = vtbl->nvars;
2418 for (i=0; i<n; i++) {
2419 x = vtbl->root[i];
2420 if (x == i) {
2421 /*
2422 * x is a root
2423 * get all composites whose function symbol is in x's class
2424 * propagate them
2425 */
2426 egraph_collect_applications(solver->egraph, vtbl->eterm[x], &v);
2427 build_apps_from_var(solver, x, &v);
2428 pvector_reset(&v);
2429 }
2430 }
2431
2432 delete_pvector(&v);
2433 }
2434
2435
2436
2437 /*
2438 * Assign a base_value to each connected component i
2439 * - we want to ensure
2440 * base_value[i] != base_value[j] ==> it's possible to assign
2441 * different default values to components i and j
2442 * - base_value[i] < 0 means that we can assign a fresh object (not in the egraph)
2443 * to component i.
2444 *
2445 * We use the following rules:
2446 * - if component i has an infinite range type, then base_value[i] = -(i+1)
2447 * - if component i has finite range type, then we count the number of
2448 * egraph class with the same type and use them as base values
2449 * - if that's smaller than the cardinality of the range type,
2450 * then we assign negative base_values to as many components as possible.
2451 */
2452 #define UNKNOWN_BASE_VALUE INT32_MAX
2453 #define NULL_BASE_VALUE INT32_MIN
2454
2455 /*
2456 * Allocate and initialize the base_value array
2457 */
fun_solver_init_base_value(fun_solver_t * solver)2458 static void fun_solver_init_base_value(fun_solver_t *solver) {
2459 uint32_t i, n;
2460 int32_t *bv;
2461
2462 assert(solver->bases_ready && solver->base_value == NULL);
2463 n = solver->num_bases;
2464 bv = (int32_t *) safe_malloc(n * sizeof(int32_t));
2465 for (i=0; i<n; i++) {
2466 bv[i] = NULL_BASE_VALUE;
2467 }
2468 solver->base_value = bv;
2469 }
2470
2471
2472
2473 /*
2474 * Comparison function for sorting the root variables
2475 * We want to group all variables of same type together.
2476 */
root_lt(fun_vartable_t * vtbl,thvar_t x,thvar_t y)2477 static bool root_lt(fun_vartable_t *vtbl, thvar_t x, thvar_t y) {
2478 assert(0 <= x && x < vtbl->nvars && vtbl->root[x] == x &&
2479 0 <= y && y < vtbl->nvars && vtbl->root[y] == y);
2480
2481 return vtbl->type[x] < vtbl->type[y];
2482 }
2483
2484
2485 /*
2486 * Assign a base value to all connected components
2487 */
fun_solver_assign_base_values(fun_solver_t * solver)2488 static void fun_solver_assign_base_values(fun_solver_t *solver) {
2489 ivector_t buffer;
2490 fun_vartable_t *vtbl;
2491 type_table_t *types;
2492 ivector_t *v;
2493 type_t tau, sigma;
2494 uint32_t i, j, h, n, m, p;
2495 thvar_t x;
2496 int32_t k;
2497
2498 assert(solver->base_value != NULL);
2499
2500 vtbl = &solver->vtbl;
2501 v = &solver->aux_vector;
2502 assert(v->size == 0);
2503
2504 /*
2505 * buffer is used only if we have functions
2506 * with finite ranges. init_ivector with size 0
2507 * does not allocate anything.
2508 */
2509 init_ivector(&buffer, 0);
2510
2511 /*
2512 * Collect a root variable from each connected
2513 * component in vector v.
2514 */
2515 n = vtbl->nvars;
2516 for (i=0; i<n; i++) {
2517 if (vtbl->root[i] == i) {
2518 k = vtbl->base[i];
2519 if (solver->base_value[k] == NULL_BASE_VALUE) {
2520 ivector_push(v, i);
2521 solver->base_value[k] = UNKNOWN_BASE_VALUE; // mark
2522 }
2523 }
2524 }
2525
2526 /*
2527 * Sort v: group the variables with the same type together
2528 */
2529 assert(v->size == solver->num_bases);
2530 int_array_sort2(v->data, v->size, vtbl, (int_cmp_fun_t) root_lt);
2531
2532 /*
2533 * Assign a base value to each connected component
2534 */
2535 types = solver->types;
2536 n = v->size;
2537 m = 0;
2538 while (m < n) {
2539 x = v->data[m];
2540 assert(vtbl->root[x] == x);
2541 tau = fun_var_type(vtbl, x);
2542
2543 for (i=m+1; i<n; i++) {
2544 x = v->data[i];
2545 assert(vtbl->root[x] == x);
2546 if (fun_var_type(vtbl, x) != tau) break;
2547 }
2548
2549 assert(m < i && i <= n);
2550
2551 /*
2552 * v->data[m ... i-1] = components of type tau (one variable per component)
2553 */
2554 sigma = function_type_range(types, tau);
2555 if (is_finite_type(types, sigma)) {
2556 /*
2557 * Finite range: we need i - m base values of type sigma
2558 */
2559 h = type_card(solver->types, sigma);
2560 p = i - m;
2561 if (p > h) p = h;
2562
2563 #if TRACE
2564 printf("---> assign base value: sigma = %"PRId32", card = %"PRIu32", num classes = %"PRIu32"\n",
2565 sigma, h, i - m);
2566 fflush(stdout);
2567 #endif
2568
2569 /*
2570 * Make the buffer large enough
2571 */
2572 resize_ivector(&buffer, p);
2573 assert(buffer.capacity >= p);
2574
2575 /*
2576 * Fill in the buffer with values from the egraph (as many as we can)
2577 * then with fresh values. Since p <= card sigma, this is sound.
2578 */
2579 h = egraph_get_labels_for_type(solver->egraph, sigma, buffer.data, p);
2580 assert(h <= p);
2581 k = -1; // negative index for fresh values if needed
2582 while (h < p) {
2583 buffer.data[h] = k;
2584 k --;
2585 h ++;
2586 }
2587
2588 /*
2589 * Assign base_values taken form buffer.data[0 .. p-1]
2590 */
2591 h = 0;
2592 for (j=m; j<i; j++) {
2593 x = v->data[j];
2594 k = vtbl->base[x];
2595 assert(solver->base_value[k] == UNKNOWN_BASE_VALUE);
2596 solver->base_value[k] = buffer.data[h];
2597 #if TRACE
2598 printf("---> base_value[%"PRId32"] = %"PRId32"\n", k, solver->base_value[k]);
2599 #endif
2600 h ++;
2601 if (h >= p) h = 0;
2602 }
2603
2604 } else {
2605 /*
2606 * Infinite range: all base values are fresh
2607 */
2608 for (j=m; j<i; j++) {
2609 x = v->data[j];
2610 k = vtbl->base[x];
2611 assert(solver->base_value[k] == UNKNOWN_BASE_VALUE);
2612 solver->base_value[k] = - (k+1); // encoding for 'fresh value'
2613 }
2614 }
2615
2616 m = i;
2617 }
2618
2619 // cleanup
2620 delete_ivector(&buffer);
2621 ivector_reset(v);
2622
2623 }
2624
2625
2626
2627 /*
2628 * Comparison between two functions defined by (v, dv) and (w, dw) respectively.
2629 * The functions are both of type [tau_1 ... tau_k --> sigma]
2630 * where tau_1, ..., tau_k and sigma are finite types.
2631 *
2632 * - v: sorted array of composites or NULL
2633 * - dv: default value outside of v's domain
2634 * - w: sorted array of composites or NULL
2635 * - dw: default value outside of w's domain
2636 * - card = approximate cardinality of the domain (tau_1 \times ... \times tau_k)
2637 * (cf types.h: card = UINT32_MAX if the real card is >= UINT32_MAX)
2638 *
2639 * Assumptions:
2640 * - every term in v and w is a composite of type [tau_1 ... tau_k --> sigma]
2641 * - dv and dw are either labels of two terms in the egraph of type sigma
2642 * or they are negative integers denoting fresh values of type sigma
2643 */
equal_mappings(fun_solver_t * solver,void ** v,void ** w,int32_t dv,int32_t dw,uint32_t card)2644 static bool equal_mappings(fun_solver_t *solver, void **v, void **w, int32_t dv, int32_t dw, uint32_t card) {
2645 egraph_t *egraph;
2646 composite_t *c, *d;
2647 uint32_t n, m, i, j, p;
2648 int32_t cmp;
2649
2650 // n = size of v
2651 // m = size of w
2652 n = 0;
2653 if (v != NULL) {
2654 n = pv_size(v);
2655 }
2656 m = 0;
2657 if (w != NULL) {
2658 m = pv_size(w);
2659 }
2660
2661 assert(n <= card && m <= card && dv != UNKNOWN_BASE_VALUE && dw != UNKNOWN_BASE_VALUE);
2662
2663 egraph = solver->egraph;
2664
2665 i = 0;
2666 j = 0;
2667 p = 0; // number of terms examined
2668 while (i < n && j < m) {
2669 c = v[i];
2670 d = w[j];
2671 if (c == d) {
2672 i ++;
2673 j ++;
2674 p ++;
2675 } else {
2676 cmp = app_cmp(egraph, c, d);
2677 if (cmp < 0) {
2678 // c < d in lex ordering
2679 if (egraph_term_label(egraph, c->id) != dw) {
2680 return false;
2681 }
2682 i ++;
2683 } else if (cmp > 0) {
2684 // c > d in lex ordering
2685 if (egraph_term_label(egraph, d->id) != dv) {
2686 return false;
2687 }
2688 j ++;
2689 } else {
2690 // c == d in lex ordering
2691 if (! egraph_equal_terms(egraph, c->id, d->id)) {
2692 return false;
2693 }
2694 i ++;
2695 j ++;
2696 }
2697 p ++;
2698 }
2699 }
2700
2701 while (i < n) {
2702 assert(j == m);
2703 c = v[i];
2704 if (egraph_term_label(egraph, c->id) != dw) {
2705 return false;
2706 }
2707 i ++;
2708 p ++;
2709 }
2710
2711 while (j < m) {
2712 assert(i == n);
2713 d = w[j];
2714 if (egraph_term_label(egraph, d->id) != dv) {
2715 return false;
2716 }
2717 j ++;
2718 p ++;
2719 }
2720
2721 assert(p <= card);
2722
2723 return p == card || dv == dw;
2724 }
2725
2726
2727
2728 /*
2729 * Check whether x1 and x2 are equal in the model.
2730 */
fun_solver_var_equal_in_model(fun_solver_t * solver,thvar_t x1,thvar_t x2)2731 static bool fun_solver_var_equal_in_model(fun_solver_t *solver, thvar_t x1, thvar_t x2) {
2732 fun_vartable_t *vtbl;
2733 int32_t b1, b2;
2734 int32_t v1, v2;
2735 uint32_t card;
2736
2737 vtbl = &solver->vtbl;
2738 x1 = vtbl->root[x1];
2739 x2 = vtbl->root[x2];
2740 assert(vtbl->root[x1] == x1 && vtbl->root[x2] == x2);
2741
2742 if (compatible_types(solver->types, fun_var_type(vtbl, x1), fun_var_type(vtbl, x2))) {
2743 b1 = vtbl->base[x1];
2744 b2 = vtbl->base[x2];
2745
2746 if (b1 != b2 && fun_var_has_infinite_domain(vtbl, x1)) {
2747 // x1 and x2 are not connected and have infinite domain
2748 // they will be made disequal in the final model
2749 assert(fun_var_has_infinite_domain(vtbl, x2));
2750 return false;
2751 }
2752
2753 v1 = solver->base_value[b1];
2754 v2 = solver->base_value[b2];
2755 card = card_of_domain_type(solver->types, fun_var_type(vtbl, x1));
2756
2757 return equal_mappings(solver, vtbl->app[x1], vtbl->app[x2], v1, v2, card);
2758
2759 } else {
2760 // x1 and x2 have incompatible types so they're distinct
2761 return false;
2762 }
2763 }
2764
2765
2766 /*
2767 * Hash function for separating distinct variables.
2768 *
2769 * For every variable x, we know the following
2770 * - its domain (sigma_1 x ... x sigma_n)
2771 * - its connected component index k = base[x]
2772 * - the default value for component k = default[x]
2773 * - the application map = array of composites = app[x]
2774 *
2775 * default[x] is either a label in the egraph or a fresh object,
2776 * distinct from any egraph term. default[x] is relevant for x if
2777 * app_size[x] < cardinality domain[x].
2778 *
2779 * We also use a sample_value(x): an index that occurs in the array x
2780 * and is such that x == y implies sample_value(x) = sample_value(y).
2781 *
2782 * To compute sample_value(x):
2783 * - if x has finite domain and default[x] is a fresh object and it's
2784 * relevant for x, sample_vlaue(x) = default[x]
2785 * - otherwise sample_value(x) = max of default[x] and egraph labels
2786 * of all elements that occur in app[x]
2787 *
2788 * Properties we use:
2789 * 1) if x == y then domain[x] = domain[y] (call it D)
2790 * 2) if x == y and D is infinite then base[x] = base[y]
2791 * 3) if x == y then sample_value(x) = sample_value(y)
2792 *
2793 * We associate the following signature with x:
2794 * sgn(x) = (n, sigma_1, b, s)
2795 * where
2796 * n = arity
2797 * sigma_1 = first domain component
2798 * b = base[x] if domain[x] is infinite
2799 * -1 if domain[x] is finite
2800 * s = sample_value(x)
2801 *
2802 * Then we have x == y implies sgn(x) = sgn(y).
2803 */
fun_solver_sample_value_for_var(fun_solver_t * solver,thvar_t x)2804 static int32_t fun_solver_sample_value_for_var(fun_solver_t *solver, thvar_t x) {
2805 fun_vartable_t *vtbl;
2806 composite_t *c;
2807 void **v;
2808 elabel_t label;
2809 uint32_t i, app_size;
2810 int32_t b, d;
2811
2812 vtbl = &solver->vtbl;
2813 assert(0 <= x && x < vtbl->nvars && vtbl->root[x] == x);
2814
2815 app_size = 0;
2816 v = vtbl->app[x];
2817 b = vtbl->base[x];
2818 d = solver->base_value[b];
2819 if (v != NULL) app_size = pv_size(v);
2820
2821 if (app_size == 0) return d;
2822
2823 if (fun_var_has_finite_domain(vtbl, x) && d < 0 &&
2824 app_size < card_of_domain_type(solver->types, fun_var_type(vtbl, x))) {
2825 return d;
2826 }
2827
2828 d = -1;
2829 for (i=0; i<app_size; i++) {
2830 c = v[i];
2831 label = egraph_term_label(solver->egraph, c->id);
2832 if (label > d) d = label;
2833 }
2834
2835 assert(d >= 0);
2836 return d;
2837 }
2838
fun_solver_model_hash(fun_solver_t * solver,thvar_t x)2839 static uint32_t fun_solver_model_hash(fun_solver_t *solver, thvar_t x) {
2840 fun_vartable_t *vtbl;
2841 int32_t sgn[4];
2842
2843 vtbl = &solver->vtbl;
2844 assert(0 <= x && x < vtbl->nvars && vtbl->root[x] == x);
2845
2846 sgn[0] = vtbl->arity[x];
2847 sgn[1] = function_type_domain(solver->types, vtbl->type[x], 0); // sigma_1
2848 sgn[2] = fun_var_has_infinite_domain(vtbl, x) ? vtbl->base[x] : -1;
2849 sgn[3] = fun_solver_sample_value_for_var(solver, x);
2850
2851 return jenkins_hash_intarray(sgn, 4);
2852 }
2853
2854
2855
2856 /*
2857 * Release model: reset apps and base labels
2858 */
fun_solver_release_model(fun_solver_t * solver)2859 static void fun_solver_release_model(fun_solver_t *solver) {
2860 fun_solver_cleanup(solver);
2861 safe_free(solver->base_value);
2862 solver->base_value = NULL;
2863 }
2864
2865
2866 /*
2867 * Build a model that attempt to minimize conflicts with the egraph.
2868 * Add instance of the extensionality axiom for the conflicts that remain.
2869 * - max_eq is ignored (we use max_extensionality instead)
2870 * - return the number of extensionality instances created
2871 * - set the reconciled_flag to true if no extensionality instances were
2872 * created (and to false otherwise).
2873 *
2874 * NOTE: this is not called if the egraph has no higher-order terms (i.e., function
2875 * terms do not occur as children of other terms, except as first term of
2876 * (update f x1 ,,, x_n u). In this case, the model construction does not
2877 * have to ensure that function variables that are in distinct classes have
2878 * distinct values.
2879 */
fun_solver_reconcile_model(fun_solver_t * solver,uint32_t max_eq)2880 uint32_t fun_solver_reconcile_model(fun_solver_t *solver, uint32_t max_eq) {
2881 fun_vartable_t *vtbl;
2882 diseq_stack_t *dstack;
2883 int_hclass_t hclass;
2884 int32_t i, x, y, n, nv0;
2885 uint32_t neq;
2886
2887 assert(!solver->bases_ready && !solver->apps_ready);
2888
2889 #if TRACE
2890 printf("\n--- FUN SOLVER: Reconcile model ---\n");
2891 print_egraph_terms(stdout, solver->egraph);
2892 printf("\n\n");
2893 fflush(stdout);
2894 #endif
2895
2896 fun_solver_build_classes(solver);
2897 fun_solver_build_components(solver);
2898 fun_solver_build_apps(solver);
2899 fun_solver_normalize_apps(solver);
2900 fun_solver_init_base_value(solver);
2901 fun_solver_assign_base_values(solver);
2902
2903 #if TRACE
2904 printf("Egraph:\n");
2905 print_egraph_terms(stdout, solver->egraph);
2906 printf("\nClasses:\n");
2907 print_fsolver_classes(stdout, solver);
2908 printf("\nMaps:\n");
2909 print_fsolver_maps(stdout, solver);
2910 printf("\nBase values\n");
2911 print_fsolver_base_values(stdout, solver);;
2912 printf("\nDisequalities:\n");
2913 print_fsolver_diseqs(stdout, solver);
2914 printf("\n");
2915 #endif
2916
2917 /*
2918 * We keep track of the current number of variables before
2919 * generating any extensionality axioms (extensionality axioms
2920 * may create new variables in this solver.
2921 */
2922 nv0 = solver->vtbl.nvars;
2923 neq = 0;
2924 max_eq = solver->max_extensionality;
2925
2926 // go through the explicit disequalities first
2927 dstack = &solver->dstack;
2928 n = dstack->top;
2929 for (i=0; i<n; i++) {
2930 x = dstack->data[i].left;
2931 y = dstack->data[i].right;
2932 if (fun_solver_var_equal_in_model(solver, x, y)) {
2933 fun_solver_extensionality_axiom(solver, x, y);
2934 neq ++;
2935 if (neq == max_eq) goto done;
2936 }
2937 }
2938
2939 /*
2940 * If the first pass has created more variables. we can't trust the
2941 * current model. So we skip the second pass.
2942 */
2943 if (nv0 < solver->vtbl.nvars) goto done;
2944
2945 // check for more conflicts between the egraph classes and the solver model.
2946 init_int_hclass(&hclass, 0, solver, (iclass_hash_fun_t) fun_solver_model_hash,
2947 (iclass_match_fun_t) fun_solver_var_equal_in_model);
2948
2949 vtbl = &solver->vtbl;
2950 n = vtbl->nvars;
2951 for (i=0; i<n; i++) {
2952 if (vtbl->root[i] == i) {
2953 x = int_hclass_get_rep(&hclass, i);
2954 if (x != i) {
2955 fun_solver_extensionality_axiom(solver, x, i);
2956 neq ++;
2957 if (neq == max_eq) break;
2958 }
2959 }
2960 }
2961
2962 delete_int_hclass(&hclass);
2963
2964 done:
2965 fun_solver_release_model(solver);
2966 solver->reconciled = (neq == 0);
2967
2968 return neq;
2969 }
2970
2971
2972
2973 /*
2974 * NEW MODEL RECONCILIATION API
2975 */
fun_solver_prepare_model(fun_solver_t * solver)2976 static void fun_solver_prepare_model(fun_solver_t *solver) {
2977 solver->reconciled = true;
2978
2979 fun_solver_build_classes(solver);
2980 fun_solver_build_components(solver);
2981 fun_solver_build_apps(solver);
2982 fun_solver_normalize_apps(solver);
2983 fun_solver_init_base_value(solver);
2984 fun_solver_assign_base_values(solver);
2985 }
2986
2987
2988 // release model is defined above
2989
2990 // equal_in_model is defined above too
2991
2992 /*
2993 * Generate the lemma l => x1 != x2
2994 * - we instantiate the extensionality axiom here:
2995 * (i.e., we generate the clause (not l) or (x1 t) /= (x2 t) for a
2996 * fresh Skolem constant t).
2997 */
fun_solver_gen_interface_lemma(fun_solver_t * solver,literal_t l,thvar_t x1,thvar_t x2,bool equiv)2998 static void fun_solver_gen_interface_lemma(fun_solver_t *solver, literal_t l, thvar_t x1, thvar_t x2, bool equiv) {
2999 fun_vartable_t *vtbl;
3000 egraph_t *egraph;
3001 ivector_t *v;
3002 eterm_t t, u;
3003 literal_t eq;
3004
3005 solver->reconciled = false;
3006
3007 assert(0 <= x1 && x1 < solver->vtbl.nvars && 0 <= x2 && x2 < solver->vtbl.nvars && x1 != x2);
3008
3009 egraph = solver->egraph;
3010 vtbl = &solver->vtbl;
3011 v = &solver->aux_vector;
3012 assert(v->size == 0);
3013
3014 fun_solver_skolem_domain(solver, vtbl->type[x1], v);
3015 t = egraph_make_apply(egraph, pos_occ(vtbl->eterm[x1]), v->size, v->data, fun_var_range_type(solver, x1));
3016 u = egraph_make_apply(egraph, pos_occ(vtbl->eterm[x2]), v->size, v->data, fun_var_range_type(solver, x2));
3017 eq = egraph_make_eq(egraph, pos_occ(t), pos_occ(u));
3018
3019 #if 0
3020 printf("---> ARRAY SOLVER: interface lemma for f!%"PRId32" /= f!%"PRId32" ----\n", x1, x2);
3021 #endif
3022
3023 #if TRACE
3024 printf("\n---> Array solver: reconciliation lemma for f!%"PRId32" /= f!%"PRId32" ----\n", x1, x2);
3025 print_eterm_def(stdout, solver->egraph, vtbl->eterm[x1]);
3026 print_eterm_def(stdout, solver->egraph, vtbl->eterm[x2]);
3027 printf("New terms:\n");
3028 print_eterm_def(stdout, egraph, t);
3029 print_eterm_def(stdout, egraph, u);
3030 printf("Antecedent:\n");
3031 print_literal(stdout, l);
3032 printf(" := ");
3033 print_egraph_atom_of_literal(stdout, egraph, l);
3034 printf("\n");
3035 printf("Disequality:\n");
3036 print_literal(stdout, eq);
3037 printf(" := ");
3038 print_egraph_atom_of_literal(stdout, egraph, eq);
3039 printf("\n");
3040 printf("Clause:\n");
3041 printf(" (OR ");
3042 print_literal(stdout, not(l));
3043 printf(" ");
3044 print_literal(stdout, not(eq));
3045 printf(")\n\n");
3046 #endif
3047
3048 add_binary_clause(solver->core, not(l), not(eq));
3049
3050 ivector_reset(v);
3051
3052 solver->stats.num_extensionality_axiom ++;
3053 }
3054
3055
3056
3057 /*************************
3058 * MODEL CONSTRUCTION *
3059 ************************/
3060
3061 /*
3062 * Collect all the root variables and group them by types
3063 * - all the root variables are added to vector roots
3064 * - they are sorted by types
3065 */
fun_solver_collect_roots(fun_solver_t * solver,ivector_t * roots)3066 static void fun_solver_collect_roots(fun_solver_t *solver, ivector_t *roots) {
3067 fun_vartable_t *vtbl;
3068 uint32_t i, n;
3069
3070 assert(roots->size == 0);
3071
3072 vtbl = &solver->vtbl;
3073 n = vtbl->nvars;
3074 for (i=0; i<n; i++) {
3075 if (vtbl->root[i] == i) {
3076 // i is a root
3077 ivector_push(roots, i);
3078 }
3079 }
3080
3081 // sort the vector
3082 int_array_sort2(roots->data, roots->size, vtbl, (int_cmp_fun_t) root_lt);
3083 }
3084
3085
3086 /*
3087 * Convert a negative base_value code into a fresh particle of type sigma
3088 * - k = code
3089 * - if sigma is finite, we use the fresh_hmap
3090 */
fun_solver_fresh_particle(fun_solver_t * solver,int32_t k,type_t sigma,pstore_t * store)3091 static particle_t fun_solver_fresh_particle(fun_solver_t *solver, int32_t k, type_t sigma, pstore_t *store) {
3092 int_hmap2_t *hmap;
3093 int_hmap2_rec_t *r;
3094 bool new;
3095 particle_t d;
3096
3097 assert(k < 0);
3098
3099 if (is_finite_type(solver->types, sigma)) {
3100 k = (- k) - 1;
3101 assert(0 <= k && k < type_card(solver->types, sigma));
3102
3103 hmap = fun_solver_get_fresh_hmap(solver);
3104 r = int_hmap2_get(hmap, sigma, k, &new);
3105 if (new) {
3106 r->val = pstore_fresh_particle(store, sigma);
3107 }
3108 d = r->val;
3109 } else {
3110 // infinite type:
3111 d = pstore_fresh_particle(store, sigma);
3112 }
3113
3114 return d;
3115 }
3116
3117
3118 /*
3119 * Convert a unary application c = (apply g i) to a pair [idx -> val]
3120 * - f = type descriptor for the function g
3121 * - idx is defined by the egraph label of i
3122 * - val is defined by the egraph label of c
3123 * - add the pair [idx -> val] to map
3124 */
convert_composite_to_map1(egraph_t * egraph,function_type_t * f,map_t * map,composite_t * c,pstore_t * store)3125 static void convert_composite_to_map1(egraph_t *egraph, function_type_t *f, map_t *map, composite_t *c, pstore_t *store) {
3126 elabel_t l_idx, l_val;
3127 particle_t idx, val;
3128
3129 assert(composite_kind(c) == COMPOSITE_APPLY && composite_arity(c) == 2 && f->ndom == 1);
3130
3131 l_idx = egraph_label(egraph, composite_child(c, 1)); // label of i
3132 l_val = egraph_term_label(egraph, c->id); // label of c
3133 idx = pstore_labeled_particle(store, l_idx, f->domain[0]);
3134 val = pstore_labeled_particle(store, l_val, f->range);
3135 add_elem_to_map(map, idx, val);
3136 }
3137
3138
3139 /*
3140 * Convert a non-unary application c = (apply g i_1 ... i_n) to a pair [idx -> val]
3141 * - f = type descriptor for function g
3142 * - idx = tuple particle for [i_1, ..., i_n]
3143 * - val is defined by the label of c in egraph
3144 * - add the pair [idx -> val] to map
3145 */
convert_composite_to_map(egraph_t * egraph,function_type_t * f,map_t * map,composite_t * c,pstore_t * store)3146 static void convert_composite_to_map(egraph_t *egraph, function_type_t *f, map_t *map, composite_t *c, pstore_t *store) {
3147 particle_t *a;
3148 uint32_t i, n;
3149 elabel_t l;
3150 particle_t idx, val;
3151 particle_t aux[10];
3152
3153 assert(composite_kind(c) == COMPOSITE_APPLY && composite_arity(c) == f->ndom + 1 && f->ndom > 1);
3154
3155 n = f->ndom;
3156 if (n <= 10) {
3157 a = aux;
3158 } else {
3159 a = safe_malloc(n * sizeof(particle_t));
3160 }
3161
3162 for (i=0; i<n; i++) {
3163 l = egraph_label(egraph, composite_child(c, i+1)); // label for i-th argument of (apply g ..)
3164 a[i] = pstore_labeled_particle(store, l, f->domain[i]); // corresponding particle
3165 }
3166
3167 idx = pstore_tuple_particle(store, n, a, f->domain); // tuple a[0 ... n-1]
3168
3169 if (n > 10) {
3170 safe_free(a);
3171 }
3172
3173 l = egraph_term_label(egraph, c->id);
3174 val = pstore_labeled_particle(store, l, f->range);
3175 add_elem_to_map(map, idx, val);
3176 }
3177
3178
3179 /*
3180 * Initialize a map for variable x
3181 * - f = the type descriptor for type of x
3182 * - store = to create particles
3183 */
build_map_for_var(fun_solver_t * solver,function_type_t * f,thvar_t x,pstore_t * store)3184 static map_t *build_map_for_var(fun_solver_t *solver, function_type_t *f, thvar_t x, pstore_t *store) {
3185 void **app;
3186 map_t *map;
3187 map_t *base_map;
3188 egraph_t *egraph;
3189 int32_t b;
3190 uint32_t i, n;
3191
3192 assert(0 <= x && x < solver->vtbl.nvars && solver->vtbl.root[x] == x);
3193
3194 app = solver->vtbl.app[x]; // set of composites for x
3195 n = 0;
3196 if (app != NULL) {
3197 n = pv_size(app);
3198 }
3199 map = new_map(n);
3200
3201 egraph = solver->egraph;
3202
3203
3204 /*
3205 * Convert each element of app into a pair [idx->value]
3206 * and add each pair to the map. Small optimization:
3207 * distinguish between unary and non-unary functions.
3208 */
3209 if (f->ndom == 1) {
3210 for (i=0; i<n; i++) {
3211 convert_composite_to_map1(egraph, f, map, app[i], store);
3212 }
3213 } else {
3214 for (i=0; i<n; i++) {
3215 convert_composite_to_map(egraph, f, map, app[i], store);
3216 }
3217 }
3218
3219 /*
3220 * Copy the default value from the base_map
3221 */
3222 b = solver->vtbl.base[x];
3223 base_map = solver->base_map[b];
3224 assert(base_map != NULL);
3225 set_map_default(map, map_default_value(base_map));
3226
3227 /*
3228 * Normalize this
3229 */
3230 normalize_map(map);
3231
3232 return map;
3233 }
3234
3235
3236
3237 /*
3238 * Collect the base maps of all elements in v[0 ... n-1]
3239 * and force these base maps to be all distinct.
3240 * - store = particle store
3241 * - f = type descriptors of all variables in v[0 ... n-1]
3242 */
fix_base_maps(fun_solver_t * solver,pstore_t * store,function_type_t * f,thvar_t * v,uint32_t n)3243 static void fix_base_maps(fun_solver_t *solver, pstore_t *store, function_type_t *f, thvar_t *v, uint32_t n) {
3244 uint8_t *mark;
3245 pvector_t w;
3246 uint32_t i, m;
3247 thvar_t x;
3248 int32_t b;
3249
3250 m = solver->num_bases;
3251 mark = (uint8_t *) safe_malloc(m * sizeof(uint8_t));
3252 for (i=0; i<m; i++) {
3253 mark[i] = false;
3254 }
3255
3256 /*
3257 * collect the base maps in vector w
3258 * mark[b] true means that base_map[b] is present in w
3259 */
3260 init_pvector(&w, m);
3261 for (i=0; i<n; i++) {
3262 x = v[i];
3263 assert(solver->vtbl.root[x] == x);
3264 b = solver->vtbl.base[x];
3265 assert(0 <= b && b < m);
3266 if (! mark[b]) {
3267 pvector_push(&w, solver->base_map[b]);
3268 mark[b] = true;
3269 }
3270 }
3271
3272 // make all elements of w differ
3273 if (! force_maps_to_differ(store, f, w.size, (map_t **) w.data)) {
3274 // BUG
3275 abort();
3276 }
3277
3278 safe_free(mark);
3279 delete_pvector(&w);
3280 }
3281
3282
3283 /*
3284 * Add the base_map for x to the current value[x]
3285 */
copy_base_map(fun_solver_t * solver,thvar_t x)3286 static void copy_base_map(fun_solver_t *solver, thvar_t x) {
3287 map_t *map;
3288 map_t *base_map;
3289 int32_t b;
3290 uint32_t i, n;
3291
3292 assert(0 <= x && x < solver->vtbl.nvars && solver->vtbl.root[x] == x);
3293
3294 map = solver->value[x];
3295 b = solver->vtbl.base[x];
3296 base_map = solver->base_map[b];
3297 assert(map != NULL && base_map != NULL);
3298
3299 n = map_num_elems(base_map);
3300 for (i=0; i<n; i++) {
3301 add_elem_to_map(map, base_map->data[i].index, base_map->data[i].value);
3302 }
3303
3304 normalize_map(map);
3305 }
3306
3307
3308
3309 /*
3310 * Build the mapping for n variables v[0,..., n-1] of type tau
3311 * - all elements of v are root variables
3312 * - tree = function tree
3313 * - store = particle store
3314 */
build_maps_for_type(fun_solver_t * solver,type_t tau,uint32_t n,thvar_t * v,fun_tree_t * tree,pstore_t * store)3315 static void build_maps_for_type(fun_solver_t *solver, type_t tau, uint32_t n, thvar_t *v,
3316 fun_tree_t *tree, pstore_t *store) {
3317 map_t *map;
3318 function_type_t *f;
3319 uint32_t i;
3320 thvar_t x;
3321 particle_t d;
3322 int32_t b;
3323 type_t sigma;
3324 bool collision;
3325
3326 assert(solver->value != NULL);
3327
3328
3329 /*
3330 * Prepare the tree for type tau
3331 */
3332 f = function_type_desc(solver->types, tau);
3333 reset_fun_tree(tree);
3334 set_fun_tree_type(tree, f);
3335
3336 /*
3337 * Build the base maps for all elements in v
3338 */
3339 sigma = function_type_range(solver->types, tau);
3340 for (i=0; i<n; i++) {
3341 x = v[i];
3342 assert(solver->vtbl.root[x] == x && solver->vtbl.base[x] >= 0);
3343 b = solver->vtbl.base[x];
3344 map = solver->base_map[b];
3345 if (map == NULL) {
3346 // get the default value for this component
3347 if (solver->base_value[b] < 0) {
3348 d = fun_solver_fresh_particle(solver, solver->base_value[b], sigma, store);
3349 } else {
3350 assert(egraph_label_is_valid(solver->egraph, solver->base_value[b]));
3351 d = pstore_labeled_particle(store, solver->base_value[b], sigma);
3352 }
3353 // the default base maps everything to d
3354 map = new_map(0);
3355 set_map_default(map, d);
3356
3357 solver->base_map[b] = map;
3358 }
3359 }
3360
3361
3362 /*
3363 * Build the initial map for each element of v
3364 * and check whether the maps are distinct.
3365 */
3366 collision = false;
3367 for (i=0; i<n; i++) {
3368 x = v[i];
3369 assert(solver->vtbl.root[x] == x && solver->value[x] == NULL);
3370 map = build_map_for_var(solver, f, x, store);
3371 solver->value[x] = map;
3372 if (solver->reconciled) {
3373 // we must force all variables to have distinct values
3374 // in the model
3375 collision = (! fun_tree_add_map(tree, map)) || collision;
3376 }
3377 }
3378
3379 if (collision) {
3380 // this should not happen unless f has finite range and infinite domain
3381 assert(solver->reconciled && is_finite_type(solver->types, sigma) &&
3382 !type_has_finite_domain(solver->types, tau));
3383
3384 // update the base maps to make them all distinct
3385 fix_base_maps(solver, store, f, v, n);
3386
3387 // propagate the new base maps to the variables in v
3388 for (i=0; i<n; i++) {
3389 x = v[i];
3390 copy_base_map(solver, x);
3391 }
3392
3393 }
3394
3395 }
3396
3397
3398
3399 /*
3400 * Build the mapping for all variables in vector v
3401 * - the variables are sorted by types in v
3402 * - all variables of v are root variables
3403 * - tree = function tree used to ensure distinct connected components (i.e., bases)
3404 * have different base maps
3405 * - store = particle store to use
3406 */
fun_solver_build_maps(fun_solver_t * solver,ivector_t * v,fun_tree_t * tree,pstore_t * store)3407 static void fun_solver_build_maps(fun_solver_t *solver, ivector_t *v, fun_tree_t *tree, pstore_t *store) {
3408 fun_vartable_t *vtbl;
3409 thvar_t *a;
3410 thvar_t x;
3411 uint32_t i, n, m;
3412 type_t tau;
3413
3414 vtbl = &solver->vtbl;
3415
3416 m = 0;
3417 n = v->size;
3418 a = v->data;
3419 while (m < n) {
3420 x = a[m];
3421 assert(vtbl->root[x] == x);
3422 tau = vtbl->type[x];
3423
3424 for (i = m+1; i<n; i++) {
3425 x = a[i];
3426 assert(vtbl->root[x] == x);
3427 if (vtbl->type[x] != tau) {
3428 assert(vtbl->type[x] > tau);
3429 break;
3430 }
3431 }
3432
3433 // vars of type tau are in a[m ... i-1]: build their maps
3434 assert(m < i && i <= n);
3435 build_maps_for_type(solver, tau, i - m, a + m, tree, store);
3436 m = i;
3437 }
3438 }
3439
3440
3441 /*
3442 * Assign a map to all root variables
3443 * - each map is of type map_t *
3444 * - it's built as a map from abstract values to abstract values (particles)
3445 * - all particles used in the construction must be created in store
3446 */
fun_solver_build_model(fun_solver_t * solver,pstore_t * store)3447 void fun_solver_build_model(fun_solver_t *solver, pstore_t *store) {
3448 ivector_t root_vector;
3449 fun_tree_t fun_tree;
3450
3451 assert(!solver->bases_ready && !solver->apps_ready);
3452
3453 #if TRACE
3454 printf("\n**** BUILD MODEL ***\n\n");
3455 print_egraph_terms(stdout, solver->egraph);
3456 printf("\n\n");
3457 print_egraph_root_classes_details(stdout, solver->egraph);
3458 #endif
3459
3460 if (solver->vtbl.nvars > 0) {
3461 // rebuild the classes, connected components, app maps, and base values
3462 fun_solver_build_classes(solver);
3463 fun_solver_build_components(solver);
3464 fun_solver_build_apps(solver);
3465 fun_solver_normalize_apps(solver);
3466 fun_solver_init_base_value(solver);
3467 fun_solver_assign_base_values(solver);
3468
3469 // allocate internal arrays of maps
3470 fun_solver_init_values(solver);
3471 fun_solver_init_base_maps(solver, solver->num_bases);
3472
3473 #if TRACE
3474 printf("\n--- Build model ---\n");
3475 printf("Classes:\n");
3476 print_fsolver_classes(stdout, solver);
3477 printf("\nDisequalities:\n");
3478 print_fsolver_diseqs(stdout, solver);
3479 printf("\nMaps:\n");
3480 print_fsolver_maps(stdout, solver);
3481 printf("\nBase values\n");
3482 print_fsolver_base_values(stdout, solver);;
3483 printf("\n\n");
3484 #endif
3485
3486 init_ivector(&root_vector, 20); // to collect the set of roots
3487 init_fun_tree(&fun_tree, store); // to ensure base maps are distinct
3488
3489 fun_solver_collect_roots(solver, &root_vector);
3490 fun_solver_build_maps(solver, &root_vector, &fun_tree, store);
3491
3492 #if TRACE
3493 printf("\n--- Build model ---\n");
3494 print_fsolver_maps(stdout, solver);
3495 printf("\n\n");
3496 print_fsolver_values(stdout, solver);
3497 printf("\n\n");
3498 #endif
3499
3500 // cleanup
3501 fun_solver_delete_base_maps(solver);
3502 fun_solver_delete_fresh_hmap(solver);
3503 delete_fun_tree(&fun_tree);
3504 delete_ivector(&root_vector);
3505 }
3506 }
3507
3508
3509 /*
3510 * Return the map assigned to theory variable x
3511 * - that's the map of root[x]
3512 * - return NULL if there's no value for x (failure of some kind)
3513 */
fun_solver_value_in_model(fun_solver_t * solver,thvar_t x)3514 map_t *fun_solver_value_in_model(fun_solver_t *solver, thvar_t x) {
3515 assert(0 <= x && x < solver->vtbl.nvars && solver->value != NULL);
3516 x = solver->vtbl.root[x];
3517 return solver->value[x];
3518 }
3519
3520
3521 /*
3522 * Free all internal structures used in the model construction
3523 */
fun_solver_free_model(fun_solver_t * solver)3524 void fun_solver_free_model(fun_solver_t *solver) {
3525 if (solver->vtbl.nvars > 0) {
3526 fun_solver_delete_values(solver);
3527 fun_solver_cleanup(solver);
3528 safe_free(solver->base_value);
3529 solver->base_value = NULL;
3530 }
3531 }
3532
3533
3534
3535 /********************************
3536 * GARBAGE COLLECTION SUPPORT *
3537 *******************************/
3538
3539 /*
3540 * Mark all types used by solver (protect them from deletion in type_table_gc)
3541 * - scan the variable table and mark every type in table->type[x]
3542 */
fun_solver_gc_mark(fun_solver_t * solver)3543 void fun_solver_gc_mark(fun_solver_t *solver) {
3544 fun_vartable_t *vtbl;
3545 type_table_t *types;
3546 uint32_t i, n;
3547
3548 types = solver->types;
3549 vtbl = &solver->vtbl;
3550 n = vtbl->nvars;
3551 for (i=0; i<n; i++) {
3552 type_table_set_gc_mark(types, vtbl->type[i]);
3553 }
3554 }
3555
3556
3557
3558
3559
3560 /***************************
3561 * INTERFACE DESCRIPTORS *
3562 **************************/
3563
3564 /*
3565 * Control and generic interface for the egraph
3566 */
3567 static th_ctrl_interface_t fsolver_control = {
3568 (start_intern_fun_t) fun_solver_start_internalization,
3569 (start_fun_t) fun_solver_start_search,
3570 (propagate_fun_t) fun_solver_propagate,
3571 (final_check_fun_t) fun_solver_final_check,
3572 (increase_level_fun_t) fun_solver_increase_decision_level,
3573 (backtrack_fun_t) fun_solver_backtrack,
3574 (push_fun_t) fun_solver_push,
3575 (pop_fun_t) fun_solver_pop,
3576 (reset_fun_t) fun_solver_reset,
3577 (clear_fun_t) fun_solver_clear,
3578 };
3579
3580 static th_egraph_interface_t fsolver_egraph = {
3581 (assert_eq_fun_t) fun_solver_assert_var_eq,
3582 (assert_diseq_fun_t) fun_solver_assert_var_diseq,
3583 (assert_distinct_fun_t) fun_solver_assert_var_distinct,
3584 (check_diseq_fun_t) fun_solver_check_disequality,
3585 (is_constant_fun_t) fun_solver_var_is_constant,
3586 NULL, // no need for expand_th_explanation
3587 (reconcile_model_fun_t) fun_solver_reconcile_model,
3588 (prepare_model_fun_t) fun_solver_prepare_model,
3589 (equal_in_model_fun_t) fun_solver_var_equal_in_model,
3590 (gen_inter_lemma_fun_t) fun_solver_gen_interface_lemma, // gen_interface_lemma
3591 (release_model_fun_t) fun_solver_release_model,
3592 NULL, // build_model_partition,
3593 NULL, // release_model_partition,
3594 (attach_to_var_fun_t) fun_solver_attach_eterm,
3595 (get_eterm_fun_t) fun_solver_get_eterm_of_var,
3596 (select_eq_polarity_fun_t) fun_solver_select_eq_polarity,
3597 };
3598
3599
3600 /*
3601 * Fun-theory interface for the egraph
3602 */
3603 static fun_egraph_interface_t fsolver_fun_egraph = {
3604 (make_fun_var_fun_t) fun_solver_create_var,
3605 (fun_build_model_fun_t) fun_solver_build_model,
3606 (fun_val_fun_t) fun_solver_value_in_model,
3607 (fun_free_model_fun_t) fun_solver_free_model,
3608 };
3609
3610
3611
3612 /*
3613 * Access to the interface descriptors
3614 */
fun_solver_ctrl_interface(fun_solver_t * solver)3615 th_ctrl_interface_t *fun_solver_ctrl_interface(fun_solver_t *solver) {
3616 return &fsolver_control;
3617 }
3618
fun_solver_egraph_interface(fun_solver_t * solver)3619 th_egraph_interface_t *fun_solver_egraph_interface(fun_solver_t *solver) {
3620 return &fsolver_egraph;
3621 }
3622
fun_solver_fun_egraph_interface(fun_solver_t * solver)3623 fun_egraph_interface_t *fun_solver_fun_egraph_interface(fun_solver_t *solver) {
3624 return &fsolver_fun_egraph;
3625 }
3626
3627
3628