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