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