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  * INCREMENTAL FORM OF THE FLOYD-WARSHALL ALGORITHM
21  */
22 
23 
24 /*
25  * We assume that -d-1 gives the right value for any 32bit signed
26  * integer d, including when d is (-2^31) = INT32_MIN.  This is true
27  * if signed integer operations are done modulo 2^32.  The C standard
28  * does not require this, but this can be considered safe (see the
29  * autoconf documentation).
30  */
31 
32 
33 #include <stdint.h>
34 #include <stdbool.h>
35 #include <assert.h>
36 
37 #include "solvers/floyd_warshall/idl_floyd_warshall.h"
38 #include "utils/hash_functions.h"
39 #include "utils/memalloc.h"
40 
41 
42 #define TRACE 0
43 
44 #if TRACE || !defined(NDEBUG)
45 
46 #include <stdio.h>
47 #include <inttypes.h>
48 
49 #include "solvers/floyd_warshall/idl_fw_printer.h"
50 
51 #endif
52 
53 
54 
55 /****************
56  *  EDGE STACK  *
57  ***************/
58 
59 /*
60  * Initialize the stack
61  * - n = initial size
62  */
init_edge_stack(edge_stack_t * stack,uint32_t n)63 static void init_edge_stack(edge_stack_t *stack, uint32_t n) {
64   assert(n < MAX_IDL_EDGE_STACK_SIZE);
65 
66   stack->data = (idl_edge_t *) safe_malloc(n * sizeof(idl_edge_t));
67   stack->lit = (literal_t *) safe_malloc(n * sizeof(literal_t));
68   stack->size = n;
69   stack->top = 0;
70 }
71 
72 
73 /*
74  * Make the stack 50% larger
75  */
extend_edge_stack(edge_stack_t * stack)76 static void extend_edge_stack(edge_stack_t *stack) {
77   uint32_t n;
78 
79   n = stack->size + 1;
80   n += n>>1;
81   if (n >= MAX_IDL_EDGE_STACK_SIZE) {
82     out_of_memory();
83   }
84 
85   stack->data = (idl_edge_t *) safe_realloc(stack->data, n * sizeof(idl_edge_t));
86   stack->lit = (literal_t *) safe_realloc(stack->lit, n * sizeof(literal_t));
87   stack->size = n;
88 }
89 
90 
91 /*
92  * Add an edge to the stack
93  * - x = source, y = target, c = cost, l = literal attached
94  */
push_edge(edge_stack_t * stack,int32_t x,int32_t y,int32_t c,literal_t l)95 static void push_edge(edge_stack_t *stack, int32_t x, int32_t y, int32_t c, literal_t l) {
96   uint32_t i;
97 
98   i = stack->top;
99   if (i == stack->size) {
100     extend_edge_stack(stack);
101   }
102   assert(i < stack->size);
103   stack->data[i].source = x;
104   stack->data[i].target = y;
105 #ifndef NDEBUG
106   stack->data[i].cost = c;
107 #endif
108   stack->lit[i] = l;
109   stack->top = i+1;
110 }
111 
112 
113 /*
114  * Empty the stack
115  */
reset_edge_stack(edge_stack_t * stack)116 static inline void reset_edge_stack(edge_stack_t *stack) {
117   stack->top = 0;
118 }
119 
120 
121 /*
122  * Delete the stack
123  */
delete_edge_stack(edge_stack_t * stack)124 static inline void delete_edge_stack(edge_stack_t *stack) {
125   safe_free(stack->data);
126   safe_free(stack->lit);
127   stack->data = NULL;
128   stack->lit = NULL;
129 }
130 
131 
132 
133 
134 /************
135  *  MATRIX  *
136  ***********/
137 
138 /*
139  * Initialize the matrix: size is 0
140  */
init_idl_matrix(idl_matrix_t * matrix)141 static void init_idl_matrix(idl_matrix_t *matrix) {
142   matrix->size = 0;
143   matrix->dim = 0;
144   matrix->data = NULL;
145 }
146 
147 
148 
149 /*
150  * Resize to an (n * n) matrix
151  * - if n > matrix->dim then new cells are initialized as follows:
152  * - for new x, M[x, x].id = 0, M[x, x].dist = 0
153  *   for new x and y with x != y, M[x, y].id = null_idl_edge
154  * If n < matrix->dim, then some cells are lost
155  */
resize_idl_matrix(idl_matrix_t * matrix,uint32_t n)156 static void resize_idl_matrix(idl_matrix_t *matrix, uint32_t n) {
157   uint64_t new_size;
158   uint32_t i, j, d;
159   idl_cell_t *src, *dst;
160 
161   // d = current dimension, n = new dimension
162   d = matrix->dim;
163   matrix->dim = n;
164   if (d == n) return;
165 
166   // extend the data array if it's too small
167   if (n > matrix->size) {
168     new_size = ((uint64_t) n * n) * sizeof(idl_cell_t);
169     if (n >= MAX_IDL_MATRIX_DIMENSION || new_size >= SIZE_MAX) {
170       out_of_memory();
171     }
172     matrix->data = (idl_cell_t *) safe_realloc(matrix->data, new_size);
173     matrix->size = n;
174   }
175 
176   if (d < n) {
177     // move existing cells
178     i = d;
179     while (i > 0) {
180       i --;
181       src = matrix->data + d * i;  // start of current row i
182       dst = matrix->data + n * i;  // start of new row i
183       j = d;
184       while (j > 0) {
185         j --;
186         dst[j] = src[j];
187       }
188     }
189 
190     // initialize cells [d ... n-1] in rows 0 to d-1
191     dst = matrix->data;
192     for (i=0; i<d; i++) {
193       for (j=d; j<n; j++) {
194         dst[j].id = null_idl_edge;
195       }
196       dst += n;
197     }
198 
199     // initialize cells [0 ... n-1] in rows d to n-1
200     while (i<n) {
201       for (j=0; j<n; j++) {
202         dst[j].id = null_idl_edge;
203       }
204       i ++;
205       dst += n;
206     }
207 
208     // initialize diagonal: cell i of row i, for i=d to n-1
209     for (i=d; i<n; i++) {
210       dst = matrix->data + n * i + i;
211       dst->id = 0;
212       dst->dist = 0;
213     }
214 
215   } else {
216     assert(n < d);
217 
218     // move existing cells
219     for (i=0; i<n; i++) {
220       src = matrix->data + d * i;
221       dst = matrix->data + n * i;
222       for (j=0; j<n; j++) {
223         dst[j] = src[j];
224       }
225     }
226   }
227 }
228 
229 
230 /*
231  * Reset to the empty matrix
232  */
reset_idl_matrix(idl_matrix_t * matrix)233 static inline void reset_idl_matrix(idl_matrix_t *matrix) {
234   matrix->dim = 0;
235 }
236 
237 
238 /*
239  * Delete the matrix
240  */
delete_idl_matrix(idl_matrix_t * matrix)241 static inline void delete_idl_matrix(idl_matrix_t *matrix) {
242   safe_free(matrix->data);
243   matrix->data = NULL;
244 }
245 
246 
247 /*
248  * Pointer to cell x, y
249  */
idl_cell(idl_matrix_t * m,uint32_t x,uint32_t y)250 static inline idl_cell_t *idl_cell(idl_matrix_t *m, uint32_t x, uint32_t y) {
251   assert(0 <= x && x < m->dim && 0 <= y && y < m->dim);
252   return m->data + x * m->dim + y;
253 }
254 
255 /*
256  * Pointer to the start of row x
257  */
idl_row(idl_matrix_t * m,uint32_t x)258 static inline idl_cell_t *idl_row(idl_matrix_t *m, uint32_t x) {
259   assert(0 <= x && x < m->dim);
260   return m->data + x * m->dim;
261 }
262 
263 
264 /*
265  * Distance from x to y
266  */
267 #ifndef NDEBUG
idl_dist(idl_matrix_t * m,uint32_t x,uint32_t y)268 static inline int32_t idl_dist(idl_matrix_t *m, uint32_t x, uint32_t y) {
269   return idl_cell(m, x, y)->dist;
270 }
271 #endif
272 
273 /*
274  * Edge id for path from x to y
275  */
idl_edge_id(idl_matrix_t * m,uint32_t x,uint32_t y)276 static inline int32_t idl_edge_id(idl_matrix_t *m, uint32_t x, uint32_t y) {
277   return idl_cell(m, x, y)->id;
278 }
279 
280 
281 
282 
283 /*****************
284  *  SAVED CELLS  *
285  ****************/
286 
287 /*
288  * Initialize the stack
289  * - n = initial size
290  */
init_cell_stack(cell_stack_t * stack,uint32_t n)291 static void init_cell_stack(cell_stack_t *stack, uint32_t n) {
292   assert(n < MAX_IDL_CELL_STACK_SIZE);
293 
294   stack->data = (saved_cell_t *) safe_malloc(n * sizeof(saved_cell_t));
295   stack->size = n;
296   stack->top = 0;
297 }
298 
299 
300 /*
301  * Make the stack 50% larger
302  */
extend_cell_stack(cell_stack_t * stack)303 static void extend_cell_stack(cell_stack_t *stack) {
304   uint32_t n;
305 
306   n = stack->size + 1;
307   n += n>>1;
308   if (n >= MAX_IDL_CELL_STACK_SIZE) {
309     out_of_memory();
310   }
311 
312   stack->data = (saved_cell_t *) safe_realloc(stack->data, n * sizeof(saved_cell_t));
313   stack->size = n;
314 }
315 
316 
317 /*
318  * Save cell c on top of the stack
319  * - k = index of c in the matrix
320  */
save_cell(cell_stack_t * stack,uint32_t k,idl_cell_t * c)321 static void save_cell(cell_stack_t *stack, uint32_t k, idl_cell_t *c) {
322   uint32_t i;
323 
324   i = stack->top;
325   if (i == stack->size) {
326     extend_cell_stack(stack);
327   }
328   assert(i < stack->size);
329   stack->data[i].index = k;
330   stack->data[i].saved = *c;
331   stack->top = i+1;
332 }
333 
334 
335 /*
336  * Empty the stack
337  */
reset_cell_stack(cell_stack_t * stack)338 static inline void reset_cell_stack(cell_stack_t *stack) {
339   stack->top = 0;
340 }
341 
342 
343 /*
344  * Delete the stack
345  */
delete_cell_stack(cell_stack_t * stack)346 static inline void delete_cell_stack(cell_stack_t *stack) {
347   safe_free(stack->data);
348   stack->data = NULL;
349 }
350 
351 
352 
353 
354 
355 /***********
356  *  GRAPH  *
357  **********/
358 
359 /*
360  * Initialize graph: use default sizes
361  * - store edge 0 (used as a marker for path from x to x)
362  */
init_idl_graph(idl_graph_t * graph)363 static void init_idl_graph(idl_graph_t *graph) {
364   init_idl_matrix(&graph->matrix);
365   init_edge_stack(&graph->edges, DEFAULT_IDL_EDGE_STACK_SIZE);
366   init_cell_stack(&graph->cstack, DEFAULT_IDL_CELL_STACK_SIZE);
367   init_ivector(&graph->buffer, DEFAULT_IDL_BUFFER_SIZE);
368 
369   push_edge(&graph->edges, null_idl_vertex, null_idl_vertex, 0, true_literal);
370 }
371 
372 /*
373  * Delete all
374  */
delete_idl_graph(idl_graph_t * graph)375 static void delete_idl_graph(idl_graph_t *graph) {
376   delete_cell_stack(&graph->cstack);
377   delete_edge_stack(&graph->edges);
378   delete_idl_matrix(&graph->matrix);
379   delete_ivector(&graph->buffer);
380 }
381 
382 /*
383  * Reset: empty graph
384  */
reset_idl_graph(idl_graph_t * graph)385 static void reset_idl_graph(idl_graph_t *graph) {
386   reset_idl_matrix(&graph->matrix);
387   reset_edge_stack(&graph->edges);
388   reset_cell_stack(&graph->cstack);
389   ivector_reset(&graph->buffer);
390 
391   push_edge(&graph->edges, null_idl_vertex, null_idl_vertex, 0, true_literal);
392 }
393 
394 
395 /*
396  * Resize: n = number of vertices
397  * - extend and initialize the matrix appropriately
398  */
resize_idl_graph(idl_graph_t * graph,uint32_t n)399 static inline void resize_idl_graph(idl_graph_t *graph, uint32_t n) {
400   resize_idl_matrix(&graph->matrix, n);
401 }
402 
403 
404 /*
405  * Get number of edges and saved cells
406  */
idl_graph_num_edges(idl_graph_t * graph)407 static inline uint32_t idl_graph_num_edges(idl_graph_t *graph) {
408   return graph->edges.top;
409 }
410 
idl_graph_num_cells(idl_graph_t * graph)411 static inline uint32_t idl_graph_num_cells(idl_graph_t *graph) {
412   return graph->cstack.top;
413 }
414 
415 
416 /*
417  * Auxiliary function: save cell r onto the saved cell stack
418  */
idl_graph_save_cell(idl_graph_t * graph,idl_cell_t * r)419 static inline void idl_graph_save_cell(idl_graph_t *graph, idl_cell_t *r) {
420   save_cell(&graph->cstack, r - graph->matrix.data, r);
421 }
422 
423 
424 /*
425  * Add new edge to the graph and update the matrix
426  * Save any modified cell onto the saved-cell stack
427  * - x = source vertex
428  * - y = target vertex
429  * - c = cost
430  * - l = literal for explanations
431  * - k = limit on edge ids: if a cell is modified, it is saved for backtracking
432  *   only if its edge index is less than k.
433  * Preconditions:
434  * - x and y must be valid vertices, and x must be different from y
435  * - the new edge must not introduce a negative circuit
436  */
idl_graph_add_edge(idl_graph_t * graph,int32_t x,int32_t y,int32_t c,literal_t l,int32_t k)437 static void idl_graph_add_edge(idl_graph_t *graph, int32_t x, int32_t y, int32_t c, literal_t l, int32_t k) {
438   int32_t id, z, w, d;
439   idl_cell_t *r, *s;
440   ivector_t *v;
441   idl_matrix_t *m;
442   int32_t *aux;
443   uint32_t i, n;
444 
445 #if TRACE
446   printf("---> IDL: adding edge: ");
447   print_idl_vertex(stdout, x);
448   printf(" ---> ");
449   print_idl_vertex(stdout, y);
450   printf(" cost: %"PRId32"\n", c);
451 #endif
452 
453   m = &graph->matrix;
454   assert(0 <= x && x < m->dim && 0 <= y && y < m->dim && x != y);
455 
456   id = graph->edges.top; // index of the new edge
457   push_edge(&graph->edges, x, y, c, l);
458 
459   /*
460    * collect relevant vertices in vector v:
461    * vertex z is relevant if there's a path from y to z and
462    *    c + dist(y, z) < dist(x, z)
463    * if z is not relevant then, for any vertex w, the new edge
464    * cannot reduce dist(w, z)
465    */
466   v = &graph->buffer;
467   ivector_reset(v);
468   r = idl_row(m, y);  // start of row y
469   s = idl_row(m, x);  // start of row x
470   for (z=0; z<m->dim; z++, r++, s++) {
471     // r --> cell[y, z] and s --> cell[x, z]
472     if (r->id >= 0 && (s->id < 0 || c + r->dist < s->dist)) {
473       ivector_push(v, z);
474     }
475   }
476 
477   n = v->size;
478   aux = v->data;
479 
480   /*
481    * Scan relevant vertices with respect to x:
482    * vertex w is relevant if there's a path from w to x and
483    *   dist(w, x) + c < dist(w, y)
484    */
485   r = idl_row(m, 0);
486   for (w=0; w<m->dim; w++, r += m->dim) {
487     // r[x] == cell[w, x] and r[y] == cell[w, y]
488     if (r[x].id >= 0 && (r[y].id < 0 || c + r[x].dist < r[y].dist)) {
489       // w is relevant: check D[w, z] for all z in vector v
490       for (i=0; i<n; i++) {
491         z = aux[i];
492         if (w != z) {
493           // r[z] == cell[w, z] and s --> cell[y, z]
494           s = idl_cell(m, y, z);
495           d = r[x].dist + c + s->dist; // distance w ---> x -> y ---> z
496           if (r[z].id < 0 || d < r[z].dist) {
497             // save then update cell[w, z]
498             if (r[z].id < k) {
499               idl_graph_save_cell(graph, r + z);
500             }
501             r[z].id = id;
502             r[z].dist = d;
503           }
504         }
505       }
506     }
507   }
508 
509 }
510 
511 
512 /*
513  * Backtrack: remove edges and restore the matrix
514  * - e = first edge to remove (edges of index i ... top-1) are removed
515  * - c = pointer into the saved cell stack
516  */
idl_graph_remove_edges(idl_graph_t * graph,int32_t e,uint32_t c)517 static void idl_graph_remove_edges(idl_graph_t *graph, int32_t e, uint32_t c) {
518   saved_cell_t *saved;
519   idl_cell_t *m;
520   uint32_t i, k;
521 
522   // restore the edge stack
523   assert(e > 0);
524   graph->edges.top = e;
525 
526   // restore the matrix: copy saved cells back
527   i = graph->cstack.top;
528   saved = graph->cstack.data;
529   m = graph->matrix.data;
530   while (i > c) {
531     i --;
532     k = saved[i].index;
533     m[k] = saved[i].saved;
534   }
535   graph->cstack.top = c;
536 }
537 
538 
539 
540 
541 /*
542  * Build explanation: get all literals appearing along the shortest path from x to y
543  * - the literals are stored in vector v
544  */
idl_graph_explain_path(idl_graph_t * graph,int32_t x,int32_t y,ivector_t * v)545 static void idl_graph_explain_path(idl_graph_t *graph, int32_t x, int32_t y, ivector_t *v) {
546   int32_t i;
547   literal_t l;
548 
549   if (x != y) {
550     i = idl_edge_id(&graph->matrix, x, y);
551     assert(1 <= i && i < graph->edges.top);
552     /*
553      * The shortest path from x to y is x ---> s -> t ---> y
554      * where s = source of edge i and t = target of edge i.
555      */
556     idl_graph_explain_path(graph, x, graph->edges.data[i].source, v);
557     l = graph->edges.lit[i];
558     if (l != true_literal) {
559       ivector_push(v, l);
560     }
561     idl_graph_explain_path(graph, graph->edges.data[i].target, y, v);
562   }
563 }
564 
565 
566 #ifndef NDEBUG
567 
568 /*
569  * For debugging: check consistency of the matrix
570  * - cell[x, x].id must be zero and cell[x, x].val must be 0
571  * For all x != y:
572  * - cell[x, y].id must be -1 or between 1 and number of edges -1
573  * - if cell[x, y].id == i and i != 1 then
574  *   let u = source of edge i and v = target of edge i
575  *   we must have
576  *      cell[x, u].id != 1 and cell[x, u].id < i
577  *      cell[v, y].id != 1 and cell[v, y].id < i
578  *      cell[x, y].dist = cell[x, u].dist + cost of edge i + cell[v, y].dist
579  */
valid_idl_graph(idl_graph_t * graph)580 static bool valid_idl_graph(idl_graph_t *graph) {
581   idl_matrix_t *m;
582   idl_edge_t *e;
583   int32_t x, y, i;
584   int32_t u, v;
585 
586   m = &graph->matrix;
587   for (x=0; x<m->dim; x++) {
588     for (y=0; y<m->dim; y++) {
589       i = idl_edge_id(m, x, y);
590       if (i == null_idl_edge) {
591         if (x == y) return false;
592       } else if (i == 0) {
593         if (x != y || idl_dist(m, x, y) != 0) return false;
594       } else {
595         if (x == y || i >= idl_graph_num_edges(graph)) return false;
596 
597         e = graph->edges.data + i;
598         u = e->source;
599         v = e->target;
600 
601         if (idl_edge_id(m, x, u) == null_idl_edge || idl_edge_id(m, x, u) >= i ||
602             idl_edge_id(m, v, y) == null_idl_edge || idl_edge_id(m, v, y) >= i ||
603             idl_dist(m, x, y) != idl_dist(m, x, u) + e->cost + idl_dist(m, v, y)) {
604           return false;
605         }
606       }
607     }
608   }
609 
610   return true;
611 }
612 
613 #endif
614 
615 
616 
617 /****************
618  *  ATOM TABLE  *
619  ***************/
620 
621 /*
622  * Initialize the table
623  * - n = initial size
624  */
init_idl_atbl(idl_atbl_t * table,uint32_t n)625 static void init_idl_atbl(idl_atbl_t *table, uint32_t n) {
626   idl_listelem_t *tmp;
627 
628   assert(n < MAX_IDL_ATBL_SIZE);
629 
630   table->size = n;
631   table->natoms = 0;
632   table->atoms = (idl_atom_t *) safe_malloc(n * sizeof(idl_atom_t));
633   table->mark = allocate_bitvector(n);
634 
635   // table->free_list[-1] is the list header
636   // the list is initially empty
637   tmp = (idl_listelem_t *) safe_malloc((n+1) * sizeof(idl_listelem_t));
638   tmp[0].pre = -1;
639   tmp[0].next = -1;
640   table->free_list = tmp + 1;
641 }
642 
643 
644 /*
645  * Make the table 50% larger
646  */
extend_idl_atbl(idl_atbl_t * table)647 static void extend_idl_atbl(idl_atbl_t *table) {
648   uint32_t n;
649   idl_listelem_t *tmp;
650 
651   n = table->size + 1;
652   n += n>>1;
653   if (n >= MAX_IDL_ATBL_SIZE) {
654     out_of_memory();
655   }
656 
657   table->size = n;
658   table->atoms = (idl_atom_t *) safe_realloc(table->atoms, n * sizeof(idl_atom_t));
659   table->mark = extend_bitvector(table->mark, n);
660 
661   tmp = (idl_listelem_t *) safe_realloc(table->free_list - 1, (n+1) * sizeof(idl_listelem_t));
662   table->free_list = tmp + 1;
663 }
664 
665 
666 
667 /*
668  * Add element i last into the free list
669  */
idlatom_add_last(idl_listelem_t * list,int32_t i)670 static inline void idlatom_add_last(idl_listelem_t *list, int32_t i) {
671   int32_t k;
672 
673   k = list[-1].pre; // last element
674   list[k].next = i;
675   list[i].pre = k;
676   list[i].next = -1;
677   list[-1].pre = i;
678 }
679 
680 /*
681  * Remove element i from the free list
682  * - keep list[i].next and list[i].pre unchanged so that i can be put back
683  */
idlatom_remove(idl_listelem_t * list,int32_t i)684 static inline void idlatom_remove(idl_listelem_t *list, int32_t i) {
685   int32_t j, k;
686 
687   j = list[i].next;
688   k = list[i].pre;
689   assert(list[j].pre == i && list[k].next == i);
690   list[j].pre = k;
691   list[k].next = j;
692 }
693 
694 /*
695  * Put element i back into the list
696  */
idlatom_putback(idl_listelem_t * list,int32_t i)697 static inline void idlatom_putback(idl_listelem_t *list, int32_t i) {
698   int32_t j, k;
699 
700   j = list[i].next;
701   k = list[i].pre;
702   assert(list[j].pre == k && list[k].next == j);
703   list[j].pre = i;
704   list[k].next = i;
705 }
706 
707 
708 /*
709  * Empty the list
710  */
reset_idlatom_list(idl_listelem_t * list)711 static inline void reset_idlatom_list(idl_listelem_t *list) {
712   list[-1].next = -1;
713   list[-1].pre = -1;
714 }
715 
716 
717 /*
718  * First element of the list (-1 if the list is empty)
719  */
first_in_list(idl_listelem_t * list)720 static inline int32_t first_in_list(idl_listelem_t *list) {
721   return list[-1].next;
722 }
723 
724 /*
725  * Successor of i in the list (-1 if i is the last element)
726  */
next_in_list(idl_listelem_t * list,int32_t i)727 static inline int32_t next_in_list(idl_listelem_t *list, int32_t i) {
728   return list[i].next;
729 }
730 
731 
732 
733 /*
734  * Create a new atom: (x - y <= c)
735  * returned value = the atom id
736  * boolvar is initialized to null_bvar
737  * the mark is cleared and the atom id is added to the free list
738  */
new_idl_atom(idl_atbl_t * table,int32_t x,int32_t y,int32_t c)739 static int32_t new_idl_atom(idl_atbl_t *table, int32_t x, int32_t y, int32_t c) {
740   uint32_t i;
741 
742   i = table->natoms;
743   if (i == table->size) {
744     extend_idl_atbl(table);
745   }
746   assert(i < table->size);
747   table->atoms[i].source = x;
748   table->atoms[i].target = y;
749   table->atoms[i].cost = c;
750   table->atoms[i].boolvar = null_bvar;
751 
752   clr_bit(table->mark, i);
753   idlatom_add_last(table->free_list, i);
754   table->natoms ++;
755 
756   return i;
757 }
758 
759 
760 /*
761  * Get atom descriptor for atom i
762  */
get_idl_atom(idl_atbl_t * table,int32_t i)763 static inline idl_atom_t *get_idl_atom(idl_atbl_t *table, int32_t i) {
764   assert(0 <= i && i < table->natoms);
765   return table->atoms + i;
766 }
767 
768 
769 /*
770  * Check whether atom i is assigned (i.e., marked)
771  */
idl_atom_is_assigned(idl_atbl_t * table,int32_t i)772 static inline bool idl_atom_is_assigned(idl_atbl_t *table, int32_t i) {
773   assert(0 <= i && i < table->natoms);
774   return tst_bit(table->mark, i);
775 }
776 
777 
778 /*
779  * Record that atom i is assigned: mark it, remove it from the free list
780  * - i must not be marked
781  */
mark_atom_assigned(idl_atbl_t * table,int32_t i)782 static void mark_atom_assigned(idl_atbl_t *table, int32_t i) {
783   assert(0 <= i && i < table->natoms && ! tst_bit(table->mark, i));
784   set_bit(table->mark, i);
785   idlatom_remove(table->free_list, i);
786 }
787 
788 
789 /*
790  * Record that atom i is no longer assigned: clear its mark,
791  * put it back into the free list
792  */
mark_atom_unassigned(idl_atbl_t * table,int32_t i)793 static void mark_atom_unassigned(idl_atbl_t *table, int32_t i) {
794   assert(0 <= i && i < table->natoms && tst_bit(table->mark, i));
795   clr_bit(table->mark, i);
796   idlatom_putback(table->free_list, i);
797 }
798 
799 
800 
801 
802 /*
803  * Get the index of the first unassigned atom (-1 if all atoms are assigned)
804  */
first_unassigned_atom(idl_atbl_t * table)805 static inline int32_t first_unassigned_atom(idl_atbl_t *table) {
806   return first_in_list(table->free_list);
807 }
808 
809 /*
810  * Next unassigned atom (-1 if i has no successor)
811  *
812  * Removing i from the list does not change its successor,
813  * so we can do things like
814  *   mark_atom_assigned(table, i);       // remove i from the list
815  *   i = next_unassigned_atom(table, i); // still fine.
816  */
next_unassigned_atom(idl_atbl_t * table,int32_t i)817 static inline int32_t next_unassigned_atom(idl_atbl_t *table, int32_t i) {
818   return next_in_list(table->free_list, i);
819 }
820 
821 
822 /*
823  * Remove all atoms of index >= n
824  */
restore_idl_atbl(idl_atbl_t * table,uint32_t n)825 static void restore_idl_atbl(idl_atbl_t *table, uint32_t n) {
826   uint32_t i;
827 
828   assert(n <= table->natoms);
829 
830   // remove atoms from the free list
831   for (i=n; i<table->natoms; i++) {
832     if (! tst_bit(table->mark, i)) {
833       idlatom_remove(table->free_list, i);
834     }
835   }
836   table->natoms = n;
837 }
838 
839 
840 /*
841  * Empty the table
842  */
reset_idl_atbl(idl_atbl_t * table)843 static inline void reset_idl_atbl(idl_atbl_t *table) {
844   table->natoms = 0;
845   reset_idlatom_list(table->free_list);
846 }
847 
848 
849 /*
850  * Delete the table
851  */
delete_idl_atbl(idl_atbl_t * table)852 static inline void delete_idl_atbl(idl_atbl_t *table) {
853   safe_free(table->atoms);
854   safe_free(table->free_list - 1);
855   delete_bitvector(table->mark);
856   table->atoms = NULL;
857   table->free_list = NULL;
858   table->mark = NULL;
859 }
860 
861 
862 
863 
864 /**********************************
865  *  ATOM STACK/PROPAGATION QUEUE  *
866  *********************************/
867 
868 /*
869  * Initialize: n = initial size
870  */
init_idl_astack(idl_astack_t * stack,uint32_t n)871 static void init_idl_astack(idl_astack_t *stack, uint32_t n) {
872   assert(n < MAX_IDL_ASTACK_SIZE);
873   stack->size = n;
874   stack->top = 0;
875   stack->prop_ptr = 0;
876   stack->data = (int32_t *) safe_malloc(n * sizeof(int32_t));
877 }
878 
879 /*
880  * Make the stack 50% larger
881  */
extend_idl_astack(idl_astack_t * stack)882 static void extend_idl_astack(idl_astack_t *stack) {
883   uint32_t n;
884 
885   n = stack->size + 1;
886   n += n>>1;
887   if (n >= MAX_IDL_ASTACK_SIZE) {
888     out_of_memory();
889   }
890 
891   stack->data = (int32_t *) safe_realloc(stack->data, n * sizeof(int32_t));
892   stack->size = n;
893 }
894 
895 
896 /*
897  * Usual encoding: atom id + sign bit are packed into a 32 bit integer index
898  * - the sign is 0 for positive, 1 for negative
899  * - pos_index(i) in the queue means that atom i is true
900  * - neg_index(i) in the queue means that atom i is false
901  */
pos_index(int32_t id)902 static inline int32_t pos_index(int32_t id) {
903   return id << 1;
904 }
905 
neg_index(int32_t id)906 static inline int32_t neg_index(int32_t id) {
907   return (id<<1) | 1;
908 }
909 
mk_index(int32_t id,uint32_t sign)910 static inline int32_t mk_index(int32_t id, uint32_t sign) {
911   assert(sign == 0 || sign == 1);
912   return (id<<1) | sign;
913 }
914 
atom_of_index(int32_t idx)915 static inline int32_t atom_of_index(int32_t idx) {
916   return idx>>1;
917 }
918 
sign_of_index(int32_t idx)919 static inline uint32_t sign_of_index(int32_t idx) {
920   return ((uint32_t) idx) & 1;
921 }
922 
is_pos_index(int32_t idx)923 static inline bool is_pos_index(int32_t idx) {
924   return sign_of_index(idx) == 0;
925 }
926 
927 
928 
929 /*
930  * Push atom index k on top of the stack
931  */
push_atom_index(idl_astack_t * stack,int32_t k)932 static void push_atom_index(idl_astack_t *stack, int32_t k) {
933   uint32_t i;
934 
935   i = stack->top;
936   if (i == stack->size) {
937     extend_idl_astack(stack);
938   }
939   assert(i < stack->size);
940   stack->data[i] = k;
941   stack->top = i+1;
942 }
943 
944 
945 /*
946  * Empty the stack
947  */
reset_idl_astack(idl_astack_t * stack)948 static inline void reset_idl_astack(idl_astack_t *stack) {
949   stack->top = 0;
950   stack->prop_ptr = 0;
951 }
952 
953 
954 /*
955  * Delete the stack
956  */
delete_idl_astack(idl_astack_t * stack)957 static inline void delete_idl_astack(idl_astack_t *stack) {
958   safe_free(stack->data);
959   stack->data = NULL;
960 }
961 
962 
963 
964 /****************
965  *  UNDO STACK  *
966  ***************/
967 
968 /*
969  * There's an undo record for each decision level. The record stores
970  * - edge_id = first edge created at the decision level
971  * - nsaved = number of saved cells in the graph when the decision
972  *   level was entered
973  * - natoms = number of atoms in the propagation queue when the
974  *   decision level was entered.
975  *
976  * The records are stored in stack->data[0 ... top-1] so top should
977  * always be equal to decision_level + 1.
978  *
979  * The initial record for decision level 0 must be initialized with
980  * - number of edges = -1
981  * - number of saved cells = 0
982  * - number of atoms = 0
983  */
984 
985 /*
986  * Initialize: n = size
987  */
init_idl_undo_stack(idl_undo_stack_t * stack,uint32_t n)988 static void init_idl_undo_stack(idl_undo_stack_t *stack, uint32_t n) {
989   assert(n < MAX_IDL_UNDO_STACK_SIZE);
990 
991   stack->size = n;
992   stack->top = 0;
993   stack->data = (idl_undo_record_t *) safe_malloc(n * sizeof(idl_undo_record_t));
994 }
995 
996 /*
997  * Extend the stack: make it 50% larger
998  */
extend_idl_undo_stack(idl_undo_stack_t * stack)999 static void extend_idl_undo_stack(idl_undo_stack_t *stack) {
1000   uint32_t n;
1001 
1002   n = stack->size + 1;
1003   n += n>>1;
1004   if (n >= MAX_IDL_UNDO_STACK_SIZE) {
1005     out_of_memory();
1006   }
1007   stack->size = n;
1008   stack->data = (idl_undo_record_t *) safe_realloc(stack->data, n * sizeof(idl_undo_record_t));
1009 }
1010 
1011 
1012 /*
1013  * Push record (e, c, a) on top of the stack
1014  * - e = top edge id
1015  * - c = top of the saved cell stack
1016  * - a = top of the atom stack
1017  */
push_undo_record(idl_undo_stack_t * stack,int32_t e,uint32_t c,uint32_t a)1018 static void push_undo_record(idl_undo_stack_t *stack, int32_t e, uint32_t c, uint32_t a) {
1019   uint32_t i;
1020 
1021   i = stack->top;
1022   if (i == stack->size) {
1023     extend_idl_undo_stack(stack);
1024   }
1025   assert(i < stack->size);
1026   stack->data[i].edge_id = e;
1027   stack->data[i].nsaved = c;
1028   stack->data[i].natoms = a;
1029   stack->top = i+1;
1030 }
1031 
1032 
1033 /*
1034  * Get the top record
1035  */
idl_undo_stack_top(idl_undo_stack_t * stack)1036 static inline idl_undo_record_t *idl_undo_stack_top(idl_undo_stack_t *stack) {
1037   assert(stack->top > 0);
1038   return stack->data + (stack->top - 1);
1039 }
1040 
1041 
1042 /*
1043  * Empty the stack
1044  */
reset_idl_undo_stack(idl_undo_stack_t * stack)1045 static inline void reset_idl_undo_stack(idl_undo_stack_t *stack) {
1046   stack->top = 0;
1047 }
1048 
1049 /*
1050  * Delete the stack
1051  */
delete_idl_undo_stack(idl_undo_stack_t * stack)1052 static inline void delete_idl_undo_stack(idl_undo_stack_t *stack) {
1053   safe_free(stack->data);
1054   stack->data = NULL;
1055 }
1056 
1057 
1058 
1059 /********************
1060  *  PUSH/POP STACK  *
1061  *******************/
1062 
1063 /*
1064  * Initialize: size = 0;
1065  */
init_idl_trail_stack(idl_trail_stack_t * stack)1066 static void init_idl_trail_stack(idl_trail_stack_t *stack) {
1067   stack->size = 0;
1068   stack->top = 0;
1069   stack->data = NULL;
1070 }
1071 
1072 
1073 /*
1074  * Save data for the current base_level:
1075  * - nv = number of vertices
1076  * - na = number of atoms
1077  */
idl_trail_stack_save(idl_trail_stack_t * stack,uint32_t nv,uint32_t na)1078 static void idl_trail_stack_save(idl_trail_stack_t *stack, uint32_t nv, uint32_t na) {
1079   uint32_t i, n;
1080 
1081   i = stack->top;
1082   n = stack->size;
1083   if (i == n) {
1084     if (n == 0) {
1085       n = DEFAULT_IDL_TRAIL_SIZE;
1086     } else {
1087       n += n>>1; // 50% larger
1088       if (n >= MAX_IDL_TRAIL_SIZE) {
1089         out_of_memory();
1090       }
1091     }
1092     stack->data = (idl_trail_t *) safe_realloc(stack->data, n * sizeof(idl_trail_t));
1093     stack->size = n;
1094   }
1095   assert(i < n);
1096   stack->data[i].nvertices = nv;
1097   stack->data[i].natoms = na;
1098   stack->top = i+1;
1099 }
1100 
1101 
1102 /*
1103  * Get the top record
1104  */
idl_trail_stack_top(idl_trail_stack_t * stack)1105 static inline idl_trail_t *idl_trail_stack_top(idl_trail_stack_t *stack) {
1106   assert(stack->top > 0);
1107   return stack->data + (stack->top - 1);
1108 }
1109 
1110 
1111 /*
1112  * Remove the top record
1113  */
idl_trail_stack_pop(idl_trail_stack_t * stack)1114 static inline void idl_trail_stack_pop(idl_trail_stack_t *stack) {
1115   assert(stack->top > 0);
1116   stack->top --;
1117 }
1118 
1119 
1120 /*
1121  * Empty the stack
1122  */
reset_idl_trail_stack(idl_trail_stack_t * stack)1123 static inline void reset_idl_trail_stack(idl_trail_stack_t *stack) {
1124   stack->top = 0;
1125 }
1126 
1127 
1128 /*
1129  * Delete the stack
1130  */
delete_idl_trail_stack(idl_trail_stack_t * stack)1131 static inline void delete_idl_trail_stack(idl_trail_stack_t *stack) {
1132   safe_free(stack->data);
1133   stack->data = NULL;
1134 }
1135 
1136 
1137 
1138 
1139 /*********************
1140  *  VERTEX CREATION  *
1141  ********************/
1142 
1143 /*
1144  * Create a new vertex and return its index
1145  */
idl_new_vertex(idl_solver_t * solver)1146 int32_t idl_new_vertex(idl_solver_t *solver) {
1147   uint32_t n;
1148 
1149   n = solver->nvertices;
1150   if (n >= MAX_IDL_VERTICES) {
1151     return null_idl_vertex;
1152   }
1153   solver->nvertices = n + 1;
1154   return n;
1155 }
1156 
1157 
1158 /*
1159  * Get the zero vertex (create a new vertex if needed)
1160  */
idl_zero_vertex(idl_solver_t * solver)1161 int32_t idl_zero_vertex(idl_solver_t *solver) {
1162   int32_t z;
1163 
1164   z = solver->zero_vertex;
1165   if (z == null_idl_vertex) {
1166     z = idl_new_vertex(solver);
1167     solver->zero_vertex = z;
1168   }
1169   return z;
1170 }
1171 
1172 
1173 
1174 
1175 
1176 /***************************
1177  *  HASH-CONSING OF ATOMS  *
1178  **************************/
1179 
1180 /*
1181  * Hash code for atom (x - y <= d)
1182  */
hash_idl_atom(int32_t x,int32_t y,int32_t d)1183 static inline uint32_t hash_idl_atom(int32_t x, int32_t y, int32_t d) {
1184   return jenkins_hash_triple(x, y, d, 0xa27def15);
1185 }
1186 
1187 
1188 /*
1189  * Hash consing object for interfacing with int_hash_table
1190  */
1191 typedef struct idlatom_hobj_s {
1192   int_hobj_t m;     // methods
1193   idl_atbl_t *atbl; // atom table
1194   int32_t source, target, cost; // atom components
1195 } idlatom_hobj_t;
1196 
1197 
1198 /*
1199  * Functions for int_hash_table
1200  */
hash_atom(idlatom_hobj_t * p)1201 static uint32_t hash_atom(idlatom_hobj_t *p) {
1202   return hash_idl_atom(p->source, p->target, p->cost);
1203 }
1204 
equal_atom(idlatom_hobj_t * p,int32_t id)1205 static bool equal_atom(idlatom_hobj_t *p, int32_t id) {
1206   idl_atom_t *atm;
1207 
1208   atm = get_idl_atom(p->atbl, id);
1209   return atm->source == p->source && atm->target == p->target && atm->cost == p->cost;
1210 }
1211 
build_atom(idlatom_hobj_t * p)1212 static int32_t build_atom(idlatom_hobj_t *p) {
1213   return new_idl_atom(p->atbl, p->source, p->target, p->cost);
1214 }
1215 
1216 /*
1217  * Atom constructor: use hash consing
1218  * - if the atom is new, create a fresh boolean variable v
1219  *   and the atom index to v in the core
1220  */
bvar_for_atom(idl_solver_t * solver,int32_t x,int32_t y,int32_t d)1221 static bvar_t bvar_for_atom(idl_solver_t *solver, int32_t x, int32_t y, int32_t d) {
1222   int32_t id;
1223   idl_atom_t *atm;
1224   bvar_t v;
1225   idlatom_hobj_t atom_hobj;
1226 
1227   atom_hobj.m.hash = (hobj_hash_t) hash_atom;
1228   atom_hobj.m.eq = (hobj_eq_t) equal_atom;
1229   atom_hobj.m.build = (hobj_build_t) build_atom;
1230   atom_hobj.atbl = &solver->atoms;
1231   atom_hobj.source = x;
1232   atom_hobj.target = y;
1233   atom_hobj.cost = d;
1234   id = int_htbl_get_obj(&solver->htbl, (int_hobj_t *) &atom_hobj);
1235   atm = get_idl_atom(&solver->atoms, id);
1236   v = atm->boolvar;
1237   if (v == null_bvar) {
1238     v = create_boolean_variable(solver->core);
1239     atm->boolvar = v;
1240     attach_atom_to_bvar(solver->core, v, index2atom(id));
1241   }
1242   return v;
1243 }
1244 
1245 
1246 /*
1247  * Get literal for atom (x - y <= d): simplify and normalize first
1248  */
idl_make_atom(idl_solver_t * solver,int32_t x,int32_t y,int32_t d)1249 literal_t idl_make_atom(idl_solver_t *solver, int32_t x, int32_t y, int32_t d) {
1250   assert(0 <= x && x < solver->nvertices && 0 <= y && y < solver->nvertices);
1251 
1252 #if TRACE
1253   printf("---> IDL: creating atom: ");
1254   print_idl_vertex(stdout, x);
1255   printf(" - ");
1256   print_idl_vertex(stdout, y);
1257   printf(" <= %"PRId32"\n", d);
1258   if (x == y) {
1259     if (d >= 0) {
1260       printf("---> true atom\n");
1261     } else {
1262       printf("---> false atom\n");
1263     }
1264   }
1265 #endif
1266 
1267   if (x == y) {
1268     return (d >= 0) ? true_literal : false_literal;
1269   }
1270 
1271   // EXPERIMENTAL
1272   if (solver->base_level == solver->decision_level &&
1273       x < solver->graph.matrix.dim && y < solver->graph.matrix.dim) {
1274     idl_cell_t *cell;
1275 
1276     cell = idl_cell(&solver->graph.matrix, x, y);
1277     if (cell->id >= 0 && cell->dist <= d) {
1278 #if TRACE
1279       printf("---> true atom: dist[");
1280       print_idl_vertex(stdout, x);
1281       printf(", ");
1282       print_idl_vertex(stdout, y);
1283       printf("] = %"PRId32"\n",  cell->dist);
1284 #endif
1285       return true_literal;
1286     }
1287     cell = idl_cell(&solver->graph.matrix, y, x);
1288     if (cell->id >= 0 && cell->dist < -d) {
1289 #if TRACE
1290       printf("---> false atom: dist[");
1291       print_idl_vertex(stdout, y);
1292       printf(", ");
1293       print_idl_vertex(stdout, x);
1294       printf("] = %"PRId32"\n",  cell->dist);
1295 #endif
1296       return false_literal;
1297     }
1298   }
1299 
1300   return pos_lit(bvar_for_atom(solver, x, y, d));
1301 
1302 #if 0
1303   if (x < y) {
1304     return pos_lit(bvar_for_atom(solver, x, y, d));
1305   } else {
1306     // (x - y <= d) <==> (not [y - x <= -d-1])
1307     return neg_lit(bvar_for_atom(solver, y, x, - d - 1));
1308   }
1309 #endif
1310 
1311 }
1312 
1313 
1314 
1315 
1316 
1317 
1318 
1319 
1320 
1321 /****************
1322  *  ASSERTIONS  *
1323  ***************/
1324 
1325 /*
1326  * Assert (x - y <= d) as an axiom:
1327  * - attach true_literal to the edge
1328  */
idl_add_axiom_edge(idl_solver_t * solver,int32_t x,int32_t y,int32_t d)1329 void idl_add_axiom_edge(idl_solver_t *solver, int32_t x, int32_t y, int32_t d) {
1330   idl_cell_t *cell;
1331   int32_t k;
1332 
1333   assert(0 <= x && x < solver->nvertices && 0 <= y && y < solver->nvertices);
1334   assert(solver->decision_level == solver->base_level);
1335 
1336   // do nothing if the solver is already in an inconsistent state
1337   if (solver->unsat_before_search) return;
1338 
1339   resize_idl_graph(&solver->graph, solver->nvertices);
1340 
1341   // check whether adding the edge x--->y forms a negative circuit
1342   cell = idl_cell(&solver->graph.matrix, y, x);
1343   if (cell->id >= 0 && cell->dist + d < 0) {
1344     solver->unsat_before_search = true;
1345     return;
1346   }
1347 
1348   // check whether the new axiom is redundant
1349   cell = idl_cell(&solver->graph.matrix, x, y);
1350   if (cell->id >= 0 && cell->dist <= d) {
1351     return;
1352   }
1353 
1354   /*
1355    * save limit for add_edge:
1356    * k = top edge id stored in the top record of the undo stack
1357    * if base level == 0, k = -1, so nothing will be saved
1358    */
1359   assert(solver->stack.top == solver->decision_level + 1);
1360   k = idl_undo_stack_top(&solver->stack)->edge_id;
1361 
1362   // add the edge
1363   idl_graph_add_edge(&solver->graph, x, y, d, true_literal, k);
1364 }
1365 
1366 
1367 /*
1368  * Assert (x - y == d) as an axiom: (x - y <= d && y - x <= -d)
1369  */
idl_add_axiom_eq(idl_solver_t * solver,int32_t x,int32_t y,int32_t d)1370 void idl_add_axiom_eq(idl_solver_t *solver, int32_t x, int32_t y, int32_t d) {
1371   idl_add_axiom_edge(solver, x, y, d);
1372   idl_add_axiom_edge(solver, y, x, -d);
1373 }
1374 
1375 
1376 /*
1377  * Try to assert (x - y <= d) with explanation l
1378  * - if that causes a conflict, generate the conflict explanation and return false
1379  * - return true if the edge does not cause a conflict
1380  * The graph matrix must have dimension == solver->nvertices
1381  */
idl_add_edge(idl_solver_t * solver,int32_t x,int32_t y,int32_t d,literal_t l)1382 static bool idl_add_edge(idl_solver_t *solver, int32_t x, int32_t y, int32_t d, literal_t l) {
1383   idl_cell_t *cell;
1384   int32_t k;
1385   uint32_t i, n;
1386   ivector_t *v;
1387 
1388   assert(0 <= x && x < solver->nvertices && 0 <= y && y < solver->nvertices);
1389 
1390   // check whether the new edge causes a negative circuit
1391   cell = idl_cell(&solver->graph.matrix, y, x);
1392   if (cell->id >= 0 && cell->dist + d < 0) {
1393     v = &solver->expl_buffer;
1394     ivector_reset(v);
1395     idl_graph_explain_path(&solver->graph, y, x, v);
1396     ivector_push(v, l);
1397     /*
1398      * the conflict is not (v[0] ... v[n-1])
1399      * we need to convert it to a clause and add the end marker
1400      */
1401     n = v->size;
1402     for (i=0; i<n; i++) {
1403       v->data[i] = not(v->data[i]);
1404     }
1405     ivector_push(v, null_literal); // end marker
1406     record_theory_conflict(solver->core, v->data);
1407 
1408     return false;
1409   }
1410 
1411   cell = idl_cell(&solver->graph.matrix, x, y);
1412   if (cell->id < 0 || cell->dist > d) {
1413     /*
1414      * The edge is not redundant: add it to the graph
1415      * backtrack point = number of edges on entry to the current decision level
1416      * that's stored in the top element in the undo stack
1417      */
1418     assert(solver->stack.top == solver->decision_level + 1);
1419     k = idl_undo_stack_top(&solver->stack)->edge_id;
1420     idl_graph_add_edge(&solver->graph, x, y, d, l, k);
1421   }
1422   return true;
1423 }
1424 
1425 
1426 
1427 
1428 
1429 /**************************
1430  *   THEORY PROPAGATION   *
1431  *************************/
1432 
1433 /*
1434  * Generate a propagation antecedent using the path x --> y
1435  * - return a pointer to a literal array, terminated by null_literal
1436  */
gen_idl_prop_antecedent(idl_solver_t * solver,int32_t x,int32_t y)1437 static literal_t *gen_idl_prop_antecedent(idl_solver_t *solver, int32_t x, int32_t y) {
1438   ivector_t *v;
1439   literal_t *expl;
1440   uint32_t i, n;
1441 
1442   v = &solver->expl_buffer;
1443   ivector_reset(v);
1444   idl_graph_explain_path(&solver->graph, x, y, v);
1445 
1446   // copy v + end marker into the arena
1447   n = v->size;
1448   expl = (literal_t *) arena_alloc(&solver->arena, (n + 1) * sizeof(int32_t));
1449   for (i=0; i<n; i++) {
1450     expl[i] = v->data[i];
1451   }
1452   expl[i] = null_literal;
1453 
1454   return expl;
1455 }
1456 
1457 
1458 /*
1459  * Check whether atom i (or its negation) is implied by the graph
1460  * - if so, propagate the literal to the core
1461  * - add the atom index to the propagation queue
1462  *   (this is required for backtracking)
1463  */
check_atom_for_propagation(idl_solver_t * solver,int32_t i)1464 static void check_atom_for_propagation(idl_solver_t *solver, int32_t i) {
1465   idl_atom_t *a;
1466   int32_t x, y, d;
1467   idl_cell_t *cell;
1468   literal_t *expl;
1469 
1470   assert(! idl_atom_is_assigned(&solver->atoms, i));
1471 
1472   a = get_idl_atom(&solver->atoms, i);
1473   x = a->source;
1474   y = a->target;
1475   d = a->cost;
1476 
1477   cell = idl_cell(&solver->graph.matrix, x, y);
1478   if (cell->id >= 0 && cell->dist <= d) {
1479     // d[x, y] <= d so x - y <= d is implied
1480     expl = gen_idl_prop_antecedent(solver, x, y);
1481     mark_atom_assigned(&solver->atoms, i);
1482     push_atom_index(&solver->astack, pos_index(i));
1483     propagate_literal(solver->core, pos_lit(a->boolvar), expl);
1484 #if TRACE
1485     printf("---> IDL propagation: ");
1486     print_idl_atom(stdout, a);
1487     printf(" is true: dist[");
1488     print_idl_vertex(stdout, x);
1489     printf(", ");
1490     print_idl_vertex(stdout, y);
1491     printf("] = %"PRId32"\n", cell->dist);
1492 #endif
1493     return;
1494   }
1495 
1496   cell = idl_cell(&solver->graph.matrix, y, x);
1497   if (cell->id >= 0 && cell->dist < -d) {
1498     // we have y - x <= d[y, x] < -d so x - y > d is implied
1499     expl = gen_idl_prop_antecedent(solver, y, x);
1500     mark_atom_assigned(&solver->atoms, i);
1501     push_atom_index(&solver->astack, neg_index(i));
1502     propagate_literal(solver->core, neg_lit(a->boolvar), expl);
1503 #if TRACE
1504     printf("---> IDL propagation: ");
1505     print_idl_atom(stdout, a);
1506     printf(" is false: dist[");
1507     print_idl_vertex(stdout, y);
1508     printf(", ");
1509     print_idl_vertex(stdout, x);
1510     printf("] = %"PRId32"\n", cell->dist);
1511 #endif
1512   }
1513 }
1514 
1515 
1516 
1517 /*
1518  * Scan all unassigned atoms and check propagation
1519  * - must be called after all atoms in the queue have been processed
1520  */
idl_atom_propagation(idl_solver_t * solver)1521 static void idl_atom_propagation(idl_solver_t *solver) {
1522   idl_atbl_t *tbl;
1523   int32_t i;
1524 
1525   assert(solver->astack.top == solver->astack.prop_ptr);
1526 
1527   tbl = &solver->atoms;
1528   for (i=first_unassigned_atom(tbl); i >= 0; i = next_unassigned_atom(tbl, i)) {
1529     check_atom_for_propagation(solver, i);
1530   }
1531 
1532   // update prop_ptr to skip all implied atoms in the next
1533   // call to idl_propagate.
1534   solver->astack.prop_ptr = solver->astack.top;
1535 }
1536 
1537 
1538 
1539 /********************
1540  *  SMT OPERATIONS  *
1541  *******************/
1542 
1543 /*
1544  * Start internalization: do nothing
1545  */
idl_start_internalization(idl_solver_t * solver)1546 void idl_start_internalization(idl_solver_t *solver) {
1547 }
1548 
1549 
1550 /*
1551  * Start search: if unsat flag is true, force a conflict in the core.
1552  * Otherwise, do nothing.
1553  */
idl_start_search(idl_solver_t * solver)1554 void idl_start_search(idl_solver_t *solver) {
1555   if (solver->unsat_before_search) {
1556     record_empty_theory_conflict(solver->core);
1557   }
1558 }
1559 
1560 
1561 /*
1562  * Start a new decision level:
1563  * - save the current number of edges and saved cells,
1564  *   and the size of the atom queue
1565  */
idl_increase_decision_level(idl_solver_t * solver)1566 void idl_increase_decision_level(idl_solver_t *solver) {
1567   uint32_t e, c, a;
1568 
1569   assert(! solver->unsat_before_search);
1570   assert(solver->astack.top == solver->astack.prop_ptr);
1571 
1572   e = idl_graph_num_edges(&solver->graph);
1573   c = idl_graph_num_cells(&solver->graph);
1574   a = solver->astack.top;
1575   push_undo_record(&solver->stack, e, c, a);
1576   solver->decision_level ++;
1577 
1578   // open new scope in the arena (for storing propagation antecedents)
1579   arena_push(&solver->arena);
1580 }
1581 
1582 
1583 
1584 /*
1585  * Assert atom:
1586  * - a stores the index of an atom attached to a boolean variable v
1587  * - l is either pos_lit(v) or neg_lit(v)
1588  * - pos_lit means assert atom (x - y <= c)
1589  * - neg_lit means assert its negation (y - x <= -c-1)
1590  * We just push the corresponding atom index onto the propagation queue
1591  */
idl_assert_atom(idl_solver_t * solver,void * a,literal_t l)1592 bool idl_assert_atom(idl_solver_t *solver, void *a, literal_t l) {
1593   int32_t k;
1594 
1595   k = atom2index(a);
1596   assert(var_of(l) == get_idl_atom(&solver->atoms, k)->boolvar);
1597 
1598   if (! idl_atom_is_assigned(&solver->atoms, k)) {
1599     mark_atom_assigned(&solver->atoms, k);
1600     push_atom_index(&solver->astack, mk_index(k, sign_of_lit(l)));
1601   }
1602 
1603   return true;
1604 }
1605 
1606 
1607 /*
1608  * Process all asserted atoms then propagate implied atoms to the core
1609  */
idl_propagate(idl_solver_t * solver)1610 bool idl_propagate(idl_solver_t *solver) {
1611   uint32_t i, n;
1612   int32_t k, *a;
1613   int32_t x, y, d;
1614   literal_t l;
1615   idl_atom_t *atom;
1616 
1617   resize_idl_graph(&solver->graph, solver->nvertices);
1618 
1619   a = solver->astack.data;
1620   n = solver->astack.top;
1621   for (i=solver->astack.prop_ptr; i<n; i++) {
1622     k = a[i];
1623     atom = get_idl_atom(&solver->atoms, atom_of_index(k));
1624     // turn atom or its negation into (x - y <= d)
1625     if (is_pos_index(k)) {
1626       x = atom->source;
1627       y = atom->target;
1628       d = atom->cost;
1629       l = pos_lit(atom->boolvar);
1630     } else {
1631       x = atom->target;
1632       y = atom->source;
1633       d = - atom->cost - 1;
1634       l = neg_lit(atom->boolvar);
1635     }
1636 
1637     if (! idl_add_edge(solver, x, y, d, l)) return false; // conflict
1638   }
1639 
1640   solver->astack.prop_ptr = n;
1641 
1642   assert(valid_idl_graph(&solver->graph));
1643 
1644   // theory propagation
1645   idl_atom_propagation(solver);
1646 
1647   return true;
1648 }
1649 
1650 
1651 /*
1652  * Final check: do nothing and return SAT
1653  */
idl_final_check(idl_solver_t * solver)1654 fcheck_code_t idl_final_check(idl_solver_t *solver) {
1655   return FCHECK_SAT;
1656 }
1657 
1658 
1659 /*
1660  * Clear: do nothing
1661  */
idl_clear(idl_solver_t * solver)1662 void idl_clear(idl_solver_t *solver) {
1663 }
1664 
1665 
1666 /*
1667  * Expand explanation for literal l
1668  * - l was implied with expl as antecedent
1669  * - expl is a null-terminated array of literals stored in the arena.
1670  * - v = vector where the explanation is to be added
1671  */
idl_expand_explanation(idl_solver_t * solver,literal_t l,literal_t * expl,ivector_t * v)1672 void idl_expand_explanation(idl_solver_t *solver, literal_t l, literal_t *expl, ivector_t *v) {
1673   literal_t x;
1674 
1675   for (;;) {
1676     x = *expl ++;
1677     if (x == null_literal) break;
1678     ivector_push(v, x);
1679   }
1680 }
1681 
1682 
1683 /*
1684  * Backtrack to back_level
1685  */
idl_backtrack(idl_solver_t * solver,uint32_t back_level)1686 void idl_backtrack(idl_solver_t *solver, uint32_t back_level) {
1687   idl_undo_record_t *undo;
1688   uint32_t i, n;
1689   int32_t k, *a;
1690 
1691   assert(solver->base_level <= back_level && back_level < solver->decision_level);
1692 
1693   /*
1694    * stack->data[back_level+1] = undo record created on entry to back_level + 1
1695    */
1696   assert(back_level + 1 < solver->stack.top);
1697   undo = solver->stack.data + back_level + 1;
1698   // remove all edges of level >= back_level + 1
1699   idl_graph_remove_edges(&solver->graph, undo->edge_id, undo->nsaved);
1700 
1701   /*
1702    * all atoms assigned at levels > back_level must be put back into the free list
1703    * this must be done in reverse order of atom processing
1704    */
1705   n = undo->natoms;
1706   i = solver->astack.top;
1707   a = solver->astack.data;
1708   while (i > n) {
1709     i --;
1710     k = atom_of_index(a[i]);
1711     mark_atom_unassigned(&solver->atoms, k);
1712   }
1713   solver->astack.top = n;
1714   solver->astack.prop_ptr = n;
1715 
1716   /*
1717    * Delete all temporary data in the arena
1718    */
1719   i = solver->decision_level;
1720   do {
1721     arena_pop(&solver->arena);
1722     i --;
1723   } while (i > back_level);
1724 
1725   /*
1726    * Restore the undo stack and decision_level
1727    */
1728   solver->stack.top = back_level + 1;
1729   solver->decision_level = back_level;
1730 
1731   assert(valid_idl_graph(&solver->graph));
1732 }
1733 
1734 
1735 
1736 
1737 
1738 /*
1739  * Push:
1740  * - store current number of vertices and atoms on the trail_stack
1741  * - increment both decision level and base level
1742  */
idl_push(idl_solver_t * solver)1743 void idl_push(idl_solver_t *solver) {
1744   assert(solver->base_level == solver->decision_level);
1745 
1746   dl_vartable_push(&solver->vtbl);
1747   idl_trail_stack_save(&solver->trail_stack, solver->nvertices, solver->atoms.natoms);
1748   solver->base_level ++;
1749   idl_increase_decision_level(solver);
1750   assert(solver->decision_level == solver->base_level);
1751 }
1752 
1753 
1754 /*
1755  * Pop: remove vertices and atoms created at the current base-level
1756  */
idl_pop(idl_solver_t * solver)1757 void idl_pop(idl_solver_t *solver) {
1758   idl_trail_t *top;
1759   uint32_t i, h, n, p;
1760   idl_atom_t *a;
1761 
1762   assert(solver->base_level > 0 && solver->base_level == solver->decision_level);
1763   top = idl_trail_stack_top(&solver->trail_stack);
1764 
1765   // remove variables
1766   dl_vartable_pop(&solver->vtbl);
1767 
1768   // remove atoms from the hash table
1769   p = top->natoms;
1770   n = solver->atoms.natoms;
1771   for (i = p; i<n; i++) {
1772     a = get_idl_atom(&solver->atoms, i);
1773     h = hash_idl_atom(a->source, a->target, a->cost);
1774     int_htbl_erase_record(&solver->htbl, h, i);
1775   }
1776 
1777   // remove atoms from the atom table
1778   restore_idl_atbl(&solver->atoms, n);
1779 
1780   // restore vertice count
1781   solver->nvertices = top->nvertices;
1782   resize_idl_matrix(&solver->graph.matrix, top->nvertices);
1783 
1784   // decrement base_level
1785   solver->base_level --;
1786   idl_trail_stack_pop(&solver->trail_stack);
1787 
1788   // backtrack to base_level
1789   idl_backtrack(solver, solver->base_level);
1790 
1791   assert(valid_idl_graph(&solver->graph));
1792 }
1793 
1794 
1795 /*
1796  * Reset
1797  */
idl_reset(idl_solver_t * solver)1798 void idl_reset(idl_solver_t *solver) {
1799   solver->base_level = 0;
1800   solver->decision_level = 0;
1801   solver->unsat_before_search = false;
1802 
1803   reset_dl_vartable(&solver->vtbl);
1804 
1805   solver->nvertices = 0;
1806   solver->zero_vertex = null_idl_vertex;
1807   reset_idl_graph(&solver->graph);
1808 
1809   reset_idl_atbl(&solver->atoms);
1810   reset_idl_astack(&solver->astack);
1811   reset_idl_undo_stack(&solver->stack);
1812   reset_idl_trail_stack(&solver->trail_stack);
1813 
1814   reset_int_htbl(&solver->htbl);
1815   arena_reset(&solver->arena);
1816   ivector_reset(&solver->expl_buffer);
1817   ivector_reset(&solver->aux_vector);
1818 
1819   solver->triple.target = nil_vertex;
1820   solver->triple.source = nil_vertex;
1821   q_clear(&solver->triple.constant);
1822   reset_poly_buffer(&solver->buffer);
1823 
1824   if (solver->value != NULL) {
1825     safe_free(solver->value);
1826     solver->value = NULL;
1827   }
1828 
1829   // undo record for level 0
1830   push_undo_record(&solver->stack, -1, 0, 0);
1831 
1832 }
1833 
1834 
1835 
1836 /*
1837  * THEORY-BRANCHING
1838  */
1839 
1840 /*
1841  * We compute a variable assignment using vertex 0 as a reference
1842  * using val[x] = - d[0, x].
1843  * To decide whether to case-split (x - y <= b) = true or false
1844  * we check whether val[x] - val[y] <= b.
1845  */
idl_select_polarity(idl_solver_t * solver,void * a,literal_t l)1846 literal_t idl_select_polarity(idl_solver_t *solver, void *a, literal_t l) {
1847   bvar_t v;
1848   int32_t id;
1849   idl_atom_t *atom;
1850   int32_t x, y;
1851   idl_cell_t *cell_x, *cell_y;
1852 
1853   v = var_of(l);
1854   id = atom2index(a);
1855   atom = get_idl_atom(&solver->atoms, id);
1856   assert(atom->boolvar == v);
1857 
1858   x = atom->source;
1859   y = atom->target;
1860   cell_x = idl_cell(&solver->graph.matrix, 0, x);
1861   cell_y = idl_cell(&solver->graph.matrix, 0, y);
1862   if (cell_x->id >= 0 && cell_y->id >= 0) {
1863     /*
1864      * d[0, x] and d[0, y] are defined:
1865      * val[x] - val[y] <= b iff d[0, y] - d[0, x] <= b
1866      */
1867     if (cell_y->dist - cell_x->dist <= atom->cost) {
1868       return pos_lit(v);
1869     } else {
1870       return neg_lit(v);
1871     }
1872   } else {
1873     return l;
1874   }
1875 }
1876 
1877 
1878 
1879 /**********************
1880  *  INTERNALIZATION   *
1881  *********************/
1882 
1883 /*
1884  * Raise exception or abort
1885  */
idl_exception(idl_solver_t * solver,int code)1886 static __attribute__ ((noreturn)) void idl_exception(idl_solver_t *solver, int code) {
1887   if (solver->env != NULL) {
1888     longjmp(*solver->env, code);
1889   }
1890   abort();
1891 }
1892 
1893 
1894 /*
1895  * Store a triple (x, y, c) into the internal triple
1896  * create/get the corresponding variable from vtbl.
1897  * - x = target vertex
1898  * - y = source vertex
1899  * - c = constant
1900  * This returns a variable id whose descriptor is (x - y + c).
1901  */
idl_var_for_triple(idl_solver_t * solver,int32_t x,int32_t y,int32_t c)1902 static thvar_t idl_var_for_triple(idl_solver_t *solver, int32_t x, int32_t y, int32_t c) {
1903   dl_triple_t *triple;
1904 
1905   triple = &solver->triple;
1906   triple->target = x;
1907   triple->source = y;
1908   q_set32(&triple->constant, c);
1909 
1910   return get_dl_var(&solver->vtbl, triple);
1911 }
1912 
1913 
1914 
1915 /*
1916  * Apply renaming and substitution to polynomial p
1917  * - map is a variable renaming: if p is a_0 t_0 + ... + a_n t_n
1918  *   then map[i] is the theory variable x_i that replaces t_i.
1919  * - so the function construct p = a_0 x_0 + ... + a_n x_n
1920  * The result is stored into solver->buffer.
1921  */
idl_rename_poly(idl_solver_t * solver,polynomial_t * p,thvar_t * map)1922 static void idl_rename_poly(idl_solver_t *solver, polynomial_t *p, thvar_t *map) {
1923   poly_buffer_t *b;
1924   monomial_t *mono;
1925   uint32_t i, n;
1926 
1927   b = &solver->buffer;
1928   reset_poly_buffer(b);
1929 
1930   n = p->nterms;
1931   mono = p->mono;
1932 
1933   // deal with p's constant term if any
1934   if (map[0] == null_thvar) {
1935     assert(mono[0].var == const_idx);
1936     poly_buffer_add_const(b, &mono[0].coeff);
1937     n --;
1938     map ++;
1939     mono ++;
1940   }
1941 
1942   for (i=0; i<n; i++) {
1943     assert(mono[i].var != const_idx);
1944     addmul_dl_var_to_buffer(&solver->vtbl, b, map[i], &mono[i].coeff);
1945   }
1946 
1947   normalize_poly_buffer(b);
1948 }
1949 
1950 
1951 
1952 /*
1953  * Create the zero_vertex but raise an exception if that fails.
1954  */
idl_get_zero_vertex(idl_solver_t * solver)1955 static int32_t idl_get_zero_vertex(idl_solver_t *solver) {
1956   int32_t z;
1957 
1958   z = idl_zero_vertex(solver);
1959   if (z < 0) {
1960     idl_exception(solver, TOO_MANY_ARITH_VARS);
1961   }
1962   return z;
1963 }
1964 
1965 
1966 /*
1967  * Create the atom (x - y + c) == 0 for d = (x - y + c)
1968  */
idl_eq_from_triple(idl_solver_t * solver,dl_triple_t * d)1969 static literal_t idl_eq_from_triple(idl_solver_t *solver, dl_triple_t *d) {
1970   literal_t l1, l2;
1971   int32_t c, x, y;
1972 
1973   x = d->target;
1974   y = d->source;
1975 
1976   /*
1977    * Check for trivial equality: we do this before attempting
1978    * to  convert the constant to int32.
1979    */
1980   if (x == y) {
1981     if (q_is_zero(&d->constant)) {
1982       return true_literal;
1983     } else {
1984       return false_literal;
1985     }
1986   }
1987 
1988   if (! q_get32(&d->constant, &c)) {
1989     idl_exception(solver, ARITHSOLVER_EXCEPTION);
1990   }
1991 
1992   /*
1993    * d is (x - y + c)
1994    */
1995 
1996   // a nil_vertex in triples denote 'zero'
1997   if (x < 0) {
1998     x = idl_get_zero_vertex(solver);
1999   } else if (y < 0) {
2000     y = idl_get_zero_vertex(solver);
2001   }
2002 
2003   // v == 0 is the conjunction of (y - x <= c) and (x - y <= -c)
2004   if (c == INT32_MIN) {
2005     // we can't represent -c
2006     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2007   }
2008 
2009   l1 = idl_make_atom(solver, y, x, c);  // atom (y - x <= c)
2010   l2 = idl_make_atom(solver, x, y, -c); // atom (x - y <= -c)
2011   return mk_and_gate2(solver->gate_manager, l1, l2);
2012 }
2013 
2014 
2015 /*
2016  * Create the atom (x - y + c) >= 0 for d = (x - y + c)
2017  */
idl_ge_from_triple(idl_solver_t * solver,dl_triple_t * d)2018 static literal_t idl_ge_from_triple(idl_solver_t *solver, dl_triple_t *d) {
2019   int32_t c, x, y;
2020 
2021   x = d->target;
2022   y = d->source;
2023 
2024   /*
2025    * Trivial case: don't convert the constant to int32
2026    */
2027   if (x == y) {
2028     if (q_is_nonneg(&d->constant)) {
2029       return true_literal;
2030     } else {
2031       return false_literal;
2032     }
2033   }
2034 
2035   if (! q_get32(&d->constant, &c)) {
2036     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2037   }
2038 
2039   if (x < 0) {
2040     x = idl_get_zero_vertex(solver);
2041   } else if (y < 0) {
2042     y = idl_get_zero_vertex(solver);
2043   }
2044 
2045   // (x - y + c >= 0) is (y - x <= c)
2046   return idl_make_atom(solver, y, x, c);
2047 }
2048 
2049 
2050 /*
2051  * Assert (x - y + c) == 0 or (x - y + c) != 0, given a triple d = x - y + c
2052  * - tt true: assert the equality
2053  * - tt false: assert the disequality
2054  */
idl_assert_triple_eq(idl_solver_t * solver,dl_triple_t * d,bool tt)2055 static void idl_assert_triple_eq(idl_solver_t *solver, dl_triple_t *d, bool tt) {
2056   int32_t x, y, c;
2057   literal_t l1, l2;
2058 
2059   x = d->target;
2060   y = d->source;
2061 
2062   if (x == y) {
2063     // trivial case
2064     if (q_is_zero(&d->constant) != tt) {
2065       solver->unsat_before_search = true;
2066     }
2067     return;
2068   }
2069 
2070   if (! q_get32(&d->constant, &c)) {
2071     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2072   }
2073 
2074   // d is (x - y + c)
2075   if (x < 0) {
2076     x = idl_get_zero_vertex(solver);
2077   } else if (y < 0) {
2078     y = idl_get_zero_vertex(solver);
2079   }
2080 
2081   if (tt) {
2082     // (x - y + c) == 0 is equivalent to y - x == c
2083     idl_add_axiom_eq(solver, y, x, c);
2084   } else {
2085     // (x - y + c) != 0 is equivalent to
2086     // (not (y - x <= c)) or (not (x - y <= -c))
2087     if (c == INT32_MIN) {
2088       idl_exception(solver, ARITHSOLVER_EXCEPTION);
2089     }
2090 
2091     l1 = idl_make_atom(solver, y, x, c);   // atom (y - x <= c)
2092     l2 = idl_make_atom(solver, x, y, -c);  // atom (x - y <= -c)
2093     add_binary_clause(solver->core, not(l1), not(l2));
2094   }
2095 }
2096 
2097 
2098 /*
2099  * Assert (x - y + c) >= 0 or (x - y + c) < 0, given a triple d = x - y + c
2100  * - tt true: assert  (x - y + c) >= 0
2101  * - tt false: assert (x - y + c) < 0
2102  */
idl_assert_triple_ge(idl_solver_t * solver,dl_triple_t * d,bool tt)2103 static void idl_assert_triple_ge(idl_solver_t *solver, dl_triple_t *d, bool tt) {
2104   int32_t x, y, c;
2105 
2106   x = d->target;
2107   y = d->source;
2108 
2109   if (x == y) {
2110     // trivial case
2111     if (q_is_nonneg(&d->constant) != tt) {
2112       solver->unsat_before_search = true;
2113     }
2114     return;
2115   }
2116 
2117   if (! q_get32(&d->constant, &c)) {
2118     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2119   }
2120   // d is (x - y + c)
2121 
2122   if (x < 0) {
2123     x = idl_get_zero_vertex(solver);
2124   } else if (y < 0) {
2125     y = idl_get_zero_vertex(solver);
2126   }
2127 
2128   if (tt) {
2129     // (x - y + c) >= 0 is equivalent to (y - x <= c)
2130     idl_add_axiom_edge(solver, y, x, c);
2131   } else {
2132     // (x - y + c) < 0 is equivalent to (x - y <= -c-1)
2133     // Note: (-c)-1 gives the right result even if c is INT32_MIN
2134     idl_add_axiom_edge(solver, x, y, -c-1);
2135   }
2136 }
2137 
2138 
2139 /*
2140  * TERM CONSTRUCTORS
2141  */
2142 
2143 /*
2144  * Create a new theory variable
2145  * - is_int indicates whether the variable should be an integer,
2146  *   so it should always be true for this solver.
2147  * - raise exception NOT_IDL if is_int is false
2148  * - raise exception TOO_MANY_VARS if we can't create a new vertex
2149  *   for that variable
2150  */
idl_create_var(idl_solver_t * solver,bool is_int)2151 thvar_t idl_create_var(idl_solver_t *solver, bool is_int) {
2152   int32_t v;
2153 
2154   if (! is_int) {
2155     idl_exception(solver, FORMULA_NOT_IDL);
2156   }
2157 
2158   v = idl_new_vertex(solver);
2159   if (v < 0) {
2160     idl_exception(solver, TOO_MANY_ARITH_VARS);
2161   }
2162 
2163   return idl_var_for_triple(solver, v, nil_vertex, 0);
2164 }
2165 
2166 
2167 /*
2168  * Create a variable that represents the constant q
2169  * - fails if q is not an integer
2170  */
idl_create_const(idl_solver_t * solver,rational_t * q)2171 thvar_t idl_create_const(idl_solver_t *solver, rational_t *q) {
2172   int32_t c;
2173 
2174   if (! q_get32(q, &c)) {
2175     /*
2176      * We could do a more precise diagnosis here:
2177      * There are two possibilities:
2178      * q is not an integer
2179      * q is an integer but it doesn't fit in 32bits
2180      */
2181     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2182   }
2183 
2184   return idl_var_for_triple(solver, nil_vertex, nil_vertex, c);
2185 }
2186 
2187 
2188 /*
2189  * Create a variable for a polynomial p, with variables defined by map:
2190  * - p is of the form a_0 t_0 + ... + a_n t_n where t_0, ..., t_n
2191  *   are arithmetic terms.
2192  * - map[i] is the theory variable x_i for t_i
2193  *   (with map[0] = null_thvar if t_0 is const_idx)
2194  * - the function constructs a variable equal to a_0 x_0 + ... + a_n x_n
2195  *
2196  * - fails if a_0 x_0 + ... + a_n x_n is not an IDL polynomial
2197  *   (i.e., not of the form x - y + c)
2198  */
idl_create_poly(idl_solver_t * solver,polynomial_t * p,thvar_t * map)2199 thvar_t idl_create_poly(idl_solver_t *solver, polynomial_t *p, thvar_t *map) {
2200   poly_buffer_t *b;
2201   dl_triple_t *triple;
2202 
2203   // apply renaming and substitutions
2204   idl_rename_poly(solver, p, map);
2205   b = &solver->buffer;
2206 
2207   // b contains a_0 x_0 + ... + a_n x_n
2208   triple = &solver->triple;
2209   if (! convert_poly_buffer_to_dl_triple(b, triple) ||
2210       ! q_is_int32(&triple->constant)) {
2211     /*
2212      * Exception here: either b is not of the right form
2213      * or the constant is not an integer
2214      * or the constant is an integer but it doesn't fit in 32bits
2215      */
2216     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2217   }
2218 
2219   return get_dl_var(&solver->vtbl, triple);
2220 }
2221 
2222 
2223 /*
2224  * Internalization for a product: always fails with NOT_IDL exception
2225  */
idl_create_pprod(idl_solver_t * solver,pprod_t * p,thvar_t * map)2226 thvar_t idl_create_pprod(idl_solver_t *solver, pprod_t *p, thvar_t *map) {
2227   idl_exception(solver, FORMULA_NOT_IDL);
2228 }
2229 
2230 
2231 
2232 /*
2233  * ATOM CONSTRUCTORS
2234  */
2235 
2236 /*
2237  * Create the atom v = 0
2238  */
idl_create_eq_atom(idl_solver_t * solver,thvar_t v)2239 literal_t idl_create_eq_atom(idl_solver_t *solver, thvar_t v) {
2240   return idl_eq_from_triple(solver, dl_var_triple(&solver->vtbl, v));
2241 }
2242 
2243 
2244 /*
2245  * Create the atom v >= 0
2246  */
idl_create_ge_atom(idl_solver_t * solver,thvar_t v)2247 literal_t idl_create_ge_atom(idl_solver_t *solver, thvar_t v) {
2248   return idl_ge_from_triple(solver, dl_var_triple(&solver->vtbl, v));
2249 }
2250 
2251 
2252 /*
2253  * Create the atom (v = w)
2254  */
idl_create_vareq_atom(idl_solver_t * solver,thvar_t v,thvar_t w)2255 literal_t idl_create_vareq_atom(idl_solver_t *solver, thvar_t v, thvar_t w) {
2256   dl_triple_t *triple;
2257 
2258   triple = &solver->triple;
2259   if (! diff_dl_vars(&solver->vtbl, v, w, triple)) {
2260     // v - w is not expressible as (target - source + c)
2261     idl_exception(solver, FORMULA_NOT_IDL);
2262   }
2263 
2264   return idl_eq_from_triple(solver, triple);
2265 }
2266 
2267 
2268 /*
2269  * Create the atom (p = 0)
2270  * - map = variable renaming (as in create_poly)
2271  */
idl_create_poly_eq_atom(idl_solver_t * solver,polynomial_t * p,thvar_t * map)2272 literal_t idl_create_poly_eq_atom(idl_solver_t *solver, polynomial_t *p, thvar_t *map) {
2273   poly_buffer_t *b;
2274   dl_triple_t *triple;
2275 
2276   // apply renaming and substitutions
2277   idl_rename_poly(solver, p, map);
2278 
2279   b = &solver->buffer;
2280   triple = &solver->triple;
2281   if (! rescale_poly_buffer_to_dl_triple(b, triple)) {
2282     // exception: p is not convertible to an IDL polynomial
2283     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2284   }
2285 
2286   return idl_eq_from_triple(solver, triple);
2287 }
2288 
2289 
2290 
2291 /*
2292  * Create the atom (p >= 0)
2293  * - map = variable renaming (as in create_poly)
2294  */
idl_create_poly_ge_atom(idl_solver_t * solver,polynomial_t * p,thvar_t * map)2295 literal_t idl_create_poly_ge_atom(idl_solver_t *solver, polynomial_t *p, thvar_t *map) {
2296   poly_buffer_t *b;
2297   dl_triple_t *triple;
2298 
2299   // apply renaming and substitutions
2300   idl_rename_poly(solver, p, map);
2301 
2302   b = &solver->buffer;
2303   triple = &solver->triple;
2304   if (! rescale_poly_buffer_to_dl_triple(b, triple)) {
2305     // exception: either p is not convertible to an IDL polynomial
2306     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2307   }
2308 
2309   return idl_ge_from_triple(solver, triple);
2310 }
2311 
2312 
2313 
2314 
2315 /*
2316  * TOP-LEVEL ASSERTIONS
2317  */
2318 
2319 /*
2320  * Assert the top-level constraint (v == 0) or (v != 0)
2321  * - if tt is true: assert v == 0
2322  * - if tt is false: assert v != 0
2323  */
idl_assert_eq_axiom(idl_solver_t * solver,thvar_t v,bool tt)2324 void idl_assert_eq_axiom(idl_solver_t *solver, thvar_t v, bool tt) {
2325   idl_assert_triple_eq(solver, dl_var_triple(&solver->vtbl, v), tt);
2326 }
2327 
2328 
2329 /*
2330  * Assert the top-level constraint (v >= 0) or (v < 0)
2331  * - if tt is true: assert (v >= 0)
2332  * - if tt is false: assert (v < 0)
2333  */
idl_assert_ge_axiom(idl_solver_t * solver,thvar_t v,bool tt)2334 void idl_assert_ge_axiom(idl_solver_t *solver, thvar_t v, bool tt) {
2335   idl_assert_triple_ge(solver, dl_var_triple(&solver->vtbl, v), tt);
2336 }
2337 
2338 
2339 /*
2340  * Assert (p == 0) or (p != 0) depending on tt
2341  */
idl_assert_poly_eq_axiom(idl_solver_t * solver,polynomial_t * p,thvar_t * map,bool tt)2342 void idl_assert_poly_eq_axiom(idl_solver_t *solver, polynomial_t *p, thvar_t *map, bool tt) {
2343   poly_buffer_t *b;
2344   dl_triple_t *triple;
2345 
2346   // apply renaming and substitutions
2347   idl_rename_poly(solver, p, map);
2348 
2349   b = &solver->buffer;
2350   triple = &solver->triple;
2351   if (! rescale_poly_buffer_to_dl_triple(b, triple)) {
2352     // exception: p is not convertible to an IDL polynomial
2353     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2354   }
2355 
2356   idl_assert_triple_eq(solver, triple, tt);
2357 }
2358 
2359 
2360 /*
2361  * Assert (p >= 0) or (p < 0) depending on tt
2362  */
idl_assert_poly_ge_axiom(idl_solver_t * solver,polynomial_t * p,thvar_t * map,bool tt)2363 void idl_assert_poly_ge_axiom(idl_solver_t *solver, polynomial_t *p, thvar_t *map, bool tt) {
2364   poly_buffer_t *b;
2365   dl_triple_t *triple;
2366 
2367   // apply renaming and substitutions
2368   idl_rename_poly(solver, p, map);
2369 
2370   b = &solver->buffer;
2371   triple = &solver->triple;
2372   if (! rescale_poly_buffer_to_dl_triple(b, triple)) {
2373     // exception:  p is not convertible to an IDL polynomial
2374     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2375   }
2376 
2377   idl_assert_triple_ge(solver, triple, tt);
2378 }
2379 
2380 
2381 
2382 /*
2383  * Assert (v == w) or (v != w)
2384  * - if tt is true: assert (v == w)
2385  * - if tt is false: assert (v != w)
2386  */
idl_assert_vareq_axiom(idl_solver_t * solver,thvar_t v,thvar_t w,bool tt)2387 void idl_assert_vareq_axiom(idl_solver_t *solver, thvar_t v, thvar_t w, bool tt) {
2388   dl_triple_t *triple;
2389 
2390   triple = &solver->triple;
2391   if (! diff_dl_vars(&solver->vtbl, v, w, triple)) {
2392     idl_exception(solver, FORMULA_NOT_IDL);
2393   }
2394 
2395   idl_assert_triple_eq(solver, triple, tt);
2396 }
2397 
2398 
2399 
2400 
2401 /*
2402  * Assert (c ==> v == w)
2403  */
idl_assert_cond_vareq_axiom(idl_solver_t * solver,literal_t c,thvar_t v,thvar_t w)2404 void idl_assert_cond_vareq_axiom(idl_solver_t *solver, literal_t c, thvar_t v, thvar_t w) {
2405   dl_triple_t *triple;
2406   int32_t x, y, d;
2407   literal_t l1, l2;
2408 
2409   triple = &solver->triple;
2410   if (! diff_dl_vars(&solver->vtbl, v, w, triple)) {
2411     idl_exception(solver, FORMULA_NOT_IDL);
2412   }
2413 
2414   x = triple->target;
2415   y = triple->source;
2416   // v == w is equivalent to (x - y + triple.constant) == 0
2417 
2418   if (x == y) {
2419     if (q_is_nonzero(&triple->constant)) {
2420       // (x - y + constant) == 0 is false
2421       add_unit_clause(solver->core, not(c));
2422     }
2423     return;
2424   }
2425 
2426   // convert the constant to int32_t d:
2427   if (! q_get32(&triple->constant, &d)) {
2428     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2429   }
2430 
2431   if (x < 0) {
2432     x = idl_get_zero_vertex(solver);
2433   } else if (y < 0) {
2434     y = idl_get_zero_vertex(solver);
2435   }
2436 
2437   /*
2438    * Assert (c ==> (x - y + d) == 0) as two clauses:
2439    *  c ==> (y - x <= d)
2440    *  c ==> (x - y <= -d)
2441    */
2442   if (d == INT32_MIN) {
2443     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2444   }
2445 
2446   l1 = idl_make_atom(solver, y, x, d);  // (y - x <= d)
2447   l2 = idl_make_atom(solver, x, y, -d); // (x - y <= -d)
2448   add_binary_clause(solver->core, not(c), l1);
2449   add_binary_clause(solver->core, not(c), l2);
2450 }
2451 
2452 
2453 
2454 /*
2455  * Assert (c[0] \/ .... \/ c[n-1] \/ v == w)
2456  */
idl_assert_clause_vareq_axiom(idl_solver_t * solver,uint32_t n,literal_t * c,thvar_t v,thvar_t w)2457 void idl_assert_clause_vareq_axiom(idl_solver_t *solver, uint32_t n, literal_t *c, thvar_t v, thvar_t w) {
2458   dl_triple_t *triple;
2459   ivector_t *aux;
2460   int32_t x, y, d;
2461   literal_t l1, l2;
2462 
2463   triple = &solver->triple;
2464   if (! diff_dl_vars(&solver->vtbl, v, w, triple)) {
2465     idl_exception(solver, FORMULA_NOT_IDL);
2466   }
2467 
2468   x = triple->target;
2469   y = triple->source;
2470 
2471   // v == w is equivalent to (x - y + constant) == 0
2472   if (x == y) {
2473     if (q_is_nonzero(&triple->constant)) {
2474       // (x - y + d) == 0 is false
2475       add_clause(solver->core, n, c);
2476     }
2477     return;
2478   }
2479 
2480   // convert constant to a 32bit integer
2481   if (! q_get32(&triple->constant, &d)) {
2482     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2483   }
2484 
2485   if (x < 0) {
2486     x = idl_get_zero_vertex(solver);
2487   } else if (y < 0) {
2488     y = idl_get_zero_vertex(solver);
2489   }
2490 
2491   /*
2492    * Assert two clauses:
2493    *  c[0] \/ ... \/ c[n-1] \/ (y - x <= d)
2494    *  c[0] \/ ... \/ c[n-1] \/ (x - y <= -d)
2495    */
2496   if (d == INT32_MIN) {
2497     idl_exception(solver, ARITHSOLVER_EXCEPTION);
2498   }
2499 
2500   l1 = idl_make_atom(solver, y, x, d);  // (y - x <= d)
2501   l2 = idl_make_atom(solver, x, y, -d); // (x - y <= -d)
2502 
2503   aux = &solver->aux_vector;
2504   assert(aux->size == 0);
2505   ivector_copy(aux, c, n);
2506 
2507   assert(aux->size == n);
2508   ivector_push(aux, l1);
2509   add_clause(solver->core, n+1, aux->data);
2510 
2511   aux->data[n] = l2;
2512   add_clause(solver->core, n+1, aux->data);
2513 
2514   ivector_reset(aux);
2515 }
2516 
2517 
2518 
2519 
2520 /************************
2521  *  MODEL CONSTRUCTION  *
2522  ***********************/
2523 
2524 /*
2525  * Set val[x] to vx then extend the model to predecessors of x that are
2526  * not marked: if y is not marked and there's a path from y to x, set
2527  *   val[y] := vx + d[y, x] and mark y.
2528  */
set_reference_point(idl_solver_t * solver,int32_t x,int32_t vx,byte_t * mark)2529 static void set_reference_point(idl_solver_t *solver, int32_t x, int32_t vx, byte_t *mark) {
2530   idl_matrix_t *m;
2531   idl_cell_t *cell;
2532   int32_t y, n;
2533 
2534   assert(solver->value != NULL && 0 <= x && x < solver->nvertices && ! tst_bit(mark, x));
2535 
2536   solver->value[x] = vx;
2537   set_bit(mark, x);
2538   m = &solver->graph.matrix;
2539 
2540   n = solver->nvertices;
2541   for (y=0; y<n; y++) {
2542     cell = idl_cell(m, y, x);
2543     if (cell->id > 0 && ! tst_bit(mark, y)) {
2544       set_bit(mark, y);
2545       solver->value[y] = vx + cell->dist;
2546     }
2547   }
2548 }
2549 
2550 
2551 /*
2552  * Compute val[x] for a vertex x in a new strongly connected component.
2553  * - i.e., there's no path from x to any existing marked vertex y
2554  * - we can set val[x] to anything larger than v[y] - d[y, x] where y is marked
2555  *   and a predecessor of x
2556  */
value_of_new_vertex(idl_solver_t * solver,int32_t x,byte_t * mark)2557 static int32_t value_of_new_vertex(idl_solver_t *solver, int32_t x, byte_t *mark) {
2558   idl_matrix_t *m;
2559   idl_cell_t *cell;
2560   int32_t y, n, vx, aux;
2561 
2562   vx = 0; // any default will do
2563   m = &solver->graph.matrix;
2564   n = solver->nvertices;
2565 
2566   for (y=0; y<n; y++) {
2567     cell = idl_cell(m, y, x);
2568     if (cell->id > 0 && tst_bit(mark, y)) {
2569       aux = solver->value[y] - cell->dist;
2570       if (aux > vx) {
2571         vx = aux;
2572       }
2573     }
2574   }
2575 
2576   return vx;
2577 }
2578 
2579 
2580 
2581 #ifndef NDEBUG
2582 
2583 /*
2584  * For debugging: check whether the model is good
2585  */
good_model(idl_solver_t * solver)2586 static bool good_model(idl_solver_t *solver) {
2587   idl_matrix_t *m;
2588   idl_cell_t *cell;
2589   int32_t *val;
2590   uint32_t n;
2591   int32_t x, y;
2592 
2593   m = &solver->graph.matrix;
2594   val = solver->value;
2595   n = solver->nvertices;
2596   for (x=0; x<n; x++) {
2597     for (y=0; y<n; y++) {
2598       cell = idl_cell(m, x, y);
2599       if (cell->id >= 0 && val[x] - val[y] > cell->dist) {
2600         printf("---> BUG: invalid IDL model\n");
2601         printf("   val[");
2602         print_idl_vertex(stdout, x);
2603         printf("] = %"PRId32"\n", val[x]);
2604         printf("   val[");
2605         print_idl_vertex(stdout, y);
2606         printf("] = %"PRId32"\n", val[y]);
2607         printf("   dist[");
2608         print_idl_vertex(stdout, x);
2609         printf(", ");
2610         print_idl_vertex(stdout, y);
2611         printf("] = %"PRId32"\n", cell->dist);
2612         fflush(stdout);
2613 
2614         return false;
2615       }
2616     }
2617   }
2618 
2619   return true;
2620 }
2621 
2622 #endif
2623 
2624 
2625 /*
2626  * Build a mapping from vertices to integers
2627  */
idl_build_model(idl_solver_t * solver)2628 void idl_build_model(idl_solver_t *solver) {
2629   byte_t *mark;
2630   uint32_t nvars;
2631   int32_t x, vx;
2632 
2633   assert(solver->value == NULL);
2634 
2635   nvars = solver->nvertices;
2636   solver->value = (int32_t *) safe_malloc(nvars * sizeof(int32_t));
2637   mark = allocate_bitvector0(nvars); // mark[x] = 0 for every vertex x
2638 
2639   // make sure the zero vertex has value 0
2640   x = solver->zero_vertex;
2641   if (x >= 0) {
2642     set_reference_point(solver, x, 0, mark);
2643   }
2644 
2645   // extend the model (for vertices not connected to x)
2646   for (x=0; x<nvars; x++) {
2647     if (! tst_bit(mark, x)) {
2648       vx = value_of_new_vertex(solver, x, mark);
2649       set_reference_point(solver, x, vx, mark);
2650     }
2651   }
2652 
2653   delete_bitvector(mark);
2654 
2655   assert(good_model(solver));
2656 }
2657 
2658 
2659 /*
2660  * Free the model
2661  */
idl_free_model(idl_solver_t * solver)2662 void idl_free_model(idl_solver_t *solver) {
2663   assert(solver->value != NULL);
2664   safe_free(solver->value);
2665   solver->value = NULL;
2666 }
2667 
2668 
2669 /*
2670  * Value of variable x in the model
2671  * - copy the value in v and return true
2672  */
idl_value_in_model(idl_solver_t * solver,thvar_t x,rational_t * v)2673 bool idl_value_in_model(idl_solver_t *solver, thvar_t x, rational_t *v) {
2674   dl_triple_t *d;
2675   int32_t aux;
2676 
2677   assert(solver->value != NULL && 0 <= x && x < solver->vtbl.nvars);
2678   d = dl_var_triple(&solver->vtbl, x);
2679 
2680   // d is of the form (target - source + constant)
2681   aux = 0;
2682   if (d->target >= 0) {
2683     aux = idl_vertex_value(solver, d->target);
2684   }
2685   if (d->source >= 0) {
2686     aux -= idl_vertex_value(solver, d->source);
2687   }
2688 
2689   q_set32(v, aux); // aux is the value of (target - source) in the model
2690   q_add(v, &d->constant);
2691 
2692   return true;
2693 }
2694 
2695 
2696 /*
2697  * Interface function: check whether x is an integer variable.
2698  */
idl_var_is_integer(idl_solver_t * solver,thvar_t x)2699 bool idl_var_is_integer(idl_solver_t *solver, thvar_t x) {
2700   assert(0 <= x && x < solver->vtbl.nvars);
2701   return true;
2702 }
2703 
2704 
2705 /***************************
2706  *  INTERFACE DESCRIPTORS  *
2707  **************************/
2708 
2709 /*
2710  * Control interface
2711  */
2712 static th_ctrl_interface_t idl_control = {
2713   (start_intern_fun_t) idl_start_internalization,
2714   (start_fun_t) idl_start_search,
2715   (propagate_fun_t) idl_propagate,
2716   (final_check_fun_t) idl_final_check,
2717   (increase_level_fun_t) idl_increase_decision_level,
2718   (backtrack_fun_t) idl_backtrack,
2719   (push_fun_t) idl_push,
2720   (pop_fun_t) idl_pop,
2721   (reset_fun_t) idl_reset,
2722   (clear_fun_t) idl_clear,
2723 };
2724 
2725 
2726 /*
2727  * SMT interface: delete_atom and end_atom_deletion are not supported.
2728  */
2729 static th_smt_interface_t idl_smt = {
2730   (assert_fun_t) idl_assert_atom,
2731   (expand_expl_fun_t) idl_expand_explanation,
2732   (select_pol_fun_t) idl_select_polarity,
2733   NULL,
2734   NULL,
2735 };
2736 
2737 
2738 
2739 /*
2740  * Internalization interface
2741  */
2742 static arith_interface_t idl_intern = {
2743   (create_arith_var_fun_t) idl_create_var,
2744   (create_arith_const_fun_t) idl_create_const,
2745   (create_arith_poly_fun_t) idl_create_poly,
2746   (create_arith_pprod_fun_t) idl_create_pprod,
2747 
2748   (create_arith_atom_fun_t) idl_create_eq_atom,
2749   (create_arith_atom_fun_t) idl_create_ge_atom,
2750   (create_arith_patom_fun_t) idl_create_poly_eq_atom,
2751   (create_arith_patom_fun_t) idl_create_poly_ge_atom,
2752   (create_arith_vareq_atom_fun_t) idl_create_vareq_atom,
2753 
2754   (assert_arith_axiom_fun_t) idl_assert_eq_axiom,
2755   (assert_arith_axiom_fun_t) idl_assert_ge_axiom,
2756   (assert_arith_paxiom_fun_t) idl_assert_poly_eq_axiom,
2757   (assert_arith_paxiom_fun_t) idl_assert_poly_ge_axiom,
2758   (assert_arith_vareq_axiom_fun_t) idl_assert_vareq_axiom,
2759   (assert_arith_cond_vareq_axiom_fun_t) idl_assert_cond_vareq_axiom,
2760   (assert_arith_clause_vareq_axiom_fun_t) idl_assert_clause_vareq_axiom,
2761 
2762   NULL, // attach_eterm is not supported
2763   NULL, // eterm of var is not supported
2764 
2765   (build_model_fun_t) idl_build_model,
2766   (free_model_fun_t) idl_free_model,
2767   (arith_val_in_model_fun_t) idl_value_in_model,
2768 
2769   (arith_var_is_int_fun_t) idl_var_is_integer,
2770 };
2771 
2772 
2773 
2774 
2775 /*****************
2776  *  FULL SOLVER  *
2777  ****************/
2778 
2779 /*
2780  * initialize solver:
2781  * - core = attached smt_core solver
2782  * - gates = the attached gate manager
2783  */
init_idl_solver(idl_solver_t * solver,smt_core_t * core,gate_manager_t * gates)2784 void init_idl_solver(idl_solver_t *solver, smt_core_t *core, gate_manager_t *gates) {
2785   solver->core = core;
2786   solver->gate_manager = gates;
2787   solver->base_level = 0;
2788   solver->decision_level = 0;
2789   solver->unsat_before_search = false;
2790 
2791   init_dl_vartable(&solver->vtbl);
2792 
2793   solver->nvertices = 0;
2794   solver->zero_vertex = null_idl_vertex;
2795   init_idl_graph(&solver->graph);
2796 
2797   init_idl_atbl(&solver->atoms, DEFAULT_IDL_ATBL_SIZE);
2798   init_idl_astack(&solver->astack, DEFAULT_IDL_ASTACK_SIZE);
2799   init_idl_undo_stack(&solver->stack, DEFAULT_IDL_UNDO_STACK_SIZE);
2800   init_idl_trail_stack(&solver->trail_stack);
2801 
2802   init_int_htbl(&solver->htbl, 0);
2803   init_arena(&solver->arena);
2804   init_ivector(&solver->expl_buffer, DEFAULT_IDL_BUFFER_SIZE);
2805   init_ivector(&solver->aux_vector, DEFAULT_IDL_BUFFER_SIZE);
2806 
2807   // initialize the internal triple + buffer
2808   solver->triple.target = nil_vertex;
2809   solver->triple.source = nil_vertex;
2810   q_init(&solver->triple.constant);
2811   init_poly_buffer(&solver->buffer);
2812 
2813   // this gets allocated in create_model
2814   solver->value = NULL;
2815 
2816   // no jump buffer yet
2817   solver->env = NULL;
2818 
2819   // undo record for level 0
2820   push_undo_record(&solver->stack, -1, 0, 0);
2821 
2822   assert(valid_idl_graph(&solver->graph));
2823 }
2824 
2825 
2826 /*
2827  * Delete solver
2828  */
delete_idl_solver(idl_solver_t * solver)2829 void delete_idl_solver(idl_solver_t *solver) {
2830   delete_dl_vartable(&solver->vtbl);
2831   delete_idl_graph(&solver->graph);
2832   delete_idl_atbl(&solver->atoms);
2833   delete_idl_astack(&solver->astack);
2834   delete_idl_undo_stack(&solver->stack);
2835   delete_idl_trail_stack(&solver->trail_stack);
2836 
2837   delete_int_htbl(&solver->htbl);
2838   delete_arena(&solver->arena);
2839   delete_ivector(&solver->expl_buffer);
2840   delete_ivector(&solver->aux_vector);
2841 
2842   q_clear(&solver->triple.constant);
2843   delete_poly_buffer(&solver->buffer);
2844 
2845   if (solver->value != NULL) {
2846     safe_free(solver->value);
2847     solver->value = NULL;
2848   }
2849 }
2850 
2851 
2852 
2853 /*
2854  * Attach a jump buffer
2855  */
idl_solver_init_jmpbuf(idl_solver_t * solver,jmp_buf * buffer)2856 void idl_solver_init_jmpbuf(idl_solver_t *solver, jmp_buf *buffer) {
2857   solver->env = buffer;
2858 }
2859 
2860 
2861 /*
2862  * Get the control and smt interfaces
2863  */
idl_ctrl_interface(idl_solver_t * solver)2864 th_ctrl_interface_t *idl_ctrl_interface(idl_solver_t *solver) {
2865   return &idl_control;
2866 }
2867 
idl_smt_interface(idl_solver_t * solver)2868 th_smt_interface_t *idl_smt_interface(idl_solver_t *solver) {
2869   return &idl_smt;
2870 }
2871 
2872 
2873 /*
2874  * Get the internalization interface
2875  */
idl_arith_interface(idl_solver_t * solver)2876 arith_interface_t *idl_arith_interface(idl_solver_t *solver) {
2877   return &idl_intern;
2878 }
2879