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 #include "nra_plugin_explain.h"
20 #include "nra_plugin_internal.h"
21 #include "poly_constraint.h"
22 #include "libpoly_utils.h"
23
24 #include "utils/int_hash_map.h"
25 #include "utils/pointer_vectors.h"
26 #include "mcsat/tracing.h"
27 #include "terms/term_manager.h"
28 #include "terms/rba_buffer_terms.h"
29 #include "terms/terms.h"
30
31 #include <stdlib.h>
32 #include <stdio.h>
33
34 #include <poly/poly.h>
35 #include <poly/polynomial_hash_set.h>
36 #include <poly/polynomial_vector.h>
37 #include <poly/variable_db.h>
38 #include <poly/variable_list.h>
39 #include <poly/variable_order.h>
40 #include <poly/polynomial.h>
41 #include <poly/interval.h>
42
43 static
polynomial_buffer_ensure_size(lp_polynomial_t *** buffer,uint32_t * buffer_size,uint32_t size,const lp_polynomial_context_t * ctx)44 void polynomial_buffer_ensure_size(lp_polynomial_t*** buffer, uint32_t* buffer_size, uint32_t size, const lp_polynomial_context_t* ctx) {
45 if (*buffer_size < size) {
46 uint32_t new_size = *buffer_size;
47 while (new_size < size) {
48 new_size = new_size + new_size / 2 + 10;
49 }
50 *buffer = safe_realloc(*buffer, new_size*sizeof(lp_polynomial_t*));
51 uint32_t i;
52 for (i = *buffer_size; i < new_size; ++ i) {
53 (*buffer)[i] = lp_polynomial_new(ctx);
54 }
55 *buffer_size = new_size;
56 }
57 }
58
59 static
psc_buffer_delete(lp_polynomial_t ** psc_buffer,uint32_t psc_buffer_size)60 void psc_buffer_delete(lp_polynomial_t** psc_buffer, uint32_t psc_buffer_size) {
61 uint32_t i;
62 for (i = 0; i < psc_buffer_size; ++ i) {
63 lp_polynomial_delete(psc_buffer[i]);
64 }
65 safe_free(psc_buffer);
66 }
67
68
69 struct lp_projection_map_struct {
70
71 /** All polynomials added already */
72 lp_polynomial_hash_set_t all_polynomials;
73
74 /** The sets we're maintaining */
75 lp_polynomial_hash_set_t* data;
76
77 /** Size of the data */
78 size_t data_size;
79
80 /** Size of the data */
81 size_t data_capacity;
82
83 /** Map from indices to the projection sets where it is the top variable */
84 int_hmap_t var_to_index_map;
85
86 /** List of all variables added */
87 lp_variable_list_t all_vars;
88
89 /** List of all yet unprojected variables */
90 lp_variable_list_t unprojected_vars;
91
92 /** The polynomial context */
93 const lp_polynomial_context_t* ctx;
94
95 /** The variable database */
96 const lp_variable_db_t* var_db;
97
98 /** The variable order */
99 const lp_variable_order_t* order;
100
101 /** The assignment */
102 const lp_assignment_t* m;
103
104 /** The nra plugin */
105 nra_plugin_t* nra;
106 };
107
108 typedef struct lp_projection_map_struct lp_projection_map_t;
109
110 #define LP_PROJECTION_MAP_DEFAULT_SIZE 10
111
lp_projection_map_construct(lp_projection_map_t * map,nra_plugin_t * nra)112 void lp_projection_map_construct(lp_projection_map_t* map, nra_plugin_t* nra) {
113 map->data_size = 0;
114 map->data_capacity = LP_PROJECTION_MAP_DEFAULT_SIZE;
115 map->data = safe_malloc(sizeof(lp_polynomial_hash_set_t)*map->data_capacity);
116 map->ctx = nra->lp_data.lp_ctx;
117 map->var_db = nra->lp_data.lp_var_db;
118 map->order = nra->lp_data.lp_var_order;
119 map->m = nra->lp_data.lp_assignment;
120 map->nra = nra;
121
122 lp_polynomial_hash_set_construct(&map->all_polynomials);
123 init_int_hmap(&map->var_to_index_map, 0);
124 lp_variable_list_construct(&map->all_vars);
125 lp_variable_list_construct(&map->unprojected_vars);
126 }
127
lp_projection_map_destruct(lp_projection_map_t * map)128 void lp_projection_map_destruct(lp_projection_map_t* map) {
129 size_t i;
130 for (i = 0; i < map->data_size; ++ i) {
131 lp_polynomial_hash_set_destruct(map->data + i);
132 }
133 free(map->data);
134 lp_polynomial_hash_set_destruct(&map->all_polynomials);
135 delete_int_hmap(&map->var_to_index_map);
136 lp_variable_list_destruct(&map->all_vars);
137 lp_variable_list_destruct(&map->unprojected_vars);
138 }
139
lp_projection_map_get_set_of(lp_projection_map_t * map,lp_variable_t var)140 lp_polynomial_hash_set_t* lp_projection_map_get_set_of(lp_projection_map_t* map, lp_variable_t var) {
141
142 assert(var != variable_null);
143
144 size_t var_index = 0;
145
146 // Check if already in the map
147 int_hmap_pair_t* find = int_hmap_find(&map->var_to_index_map, var);
148 if (find == NULL) {
149 // Ensure we can add new
150 if (map->data_size == map->data_capacity) {
151 map->data_capacity = map->data_capacity + map->data_capacity/2 + 10;
152 map->data = safe_realloc(map->data, sizeof(lp_polynomial_hash_set_t)*map->data_capacity);
153 }
154 // Add new
155 var_index = map->data_size;
156 lp_polynomial_hash_set_construct(map->data + var_index);
157 map->data_size ++;
158 assert(map->data_size <= map->data_capacity);
159 int_hmap_add(&map->var_to_index_map, var, var_index);
160 // Add to the list of variables
161 if (!lp_variable_list_contains(&map->all_vars, var)) {
162 lp_variable_list_push(&map->all_vars, var);
163 }
164 if (!lp_variable_list_contains(&map->unprojected_vars, var)) {
165 lp_variable_list_push(&map->unprojected_vars, var);
166 }
167 } else {
168 // Already have it
169 var_index = find->val;
170 }
171
172 return map->data + var_index;
173 }
174
175 void lp_projection_map_reduce(lp_projection_map_t* map, lp_variable_t x, const lp_polynomial_t* p, lp_polynomial_t* p_r);
176
lp_projection_map_add_if_not_there(lp_projection_map_t * map,const lp_polynomial_t * p)177 void lp_projection_map_add_if_not_there(lp_projection_map_t* map, const lp_polynomial_t* p) {
178 if (!lp_polynomial_hash_set_contains(&map->all_polynomials, p)) {
179 lp_variable_t x = lp_polynomial_top_variable(p);
180 lp_polynomial_hash_set_t* x_set = lp_projection_map_get_set_of(map, x);
181 assert(!lp_polynomial_hash_set_contains(x_set, p));
182 lp_polynomial_hash_set_insert(x_set, p);
183 lp_polynomial_hash_set_insert(&map->all_polynomials, p);
184 }
185 }
186
lp_projection_map_add(lp_projection_map_t * map,const lp_polynomial_t * p)187 void lp_projection_map_add(lp_projection_map_t* map, const lp_polynomial_t* p) {
188
189 // Don't add constants or things already there
190 if (lp_polynomial_is_constant(p) || lp_polynomial_hash_set_contains(&map->all_polynomials, p)) {
191 return;
192 }
193
194 // Reduce the polynomials and add all the vanishing coefficients
195 lp_variable_t x = lp_polynomial_top_variable(p);
196 lp_polynomial_t* p_r = lp_polynomial_new(map->ctx);
197 lp_projection_map_reduce(map, x, p, p_r);
198
199 // Don't add constants or things already there
200 if (lp_polynomial_is_constant(p_r) || lp_polynomial_hash_set_contains(&map->all_polynomials, p_r)) {
201 lp_polynomial_delete(p_r);
202 return;
203 }
204
205 // If the variable has changed, it was added in reduce
206 if (lp_polynomial_top_variable(p_r) != x) {
207 lp_polynomial_delete(p_r);
208 return;
209 }
210
211 // p_r leading coefficient doesn't vanish and it is primitive
212 // all the assumptions of this are put in the map
213
214 // Factor the polynomial. Since it's primitive, all factors are in x,
215 // their leading coefficients don't vanish
216 lp_polynomial_t** p_r_factors = 0;
217 size_t* p_r_factors_multiplicities = 0;
218 size_t p_r_factors_size = 0;
219 lp_polynomial_factor_square_free(p_r, &p_r_factors, &p_r_factors_multiplicities, &p_r_factors_size);
220
221 uint32_t i;
222
223 lp_polynomial_t* p_r_zero = NULL;
224 // If x is assigned, check if any of the factors evaluates to 0
225 if (lp_assignment_get_value(map->m, x)->type != LP_VALUE_NONE) {
226 for (i = 0; i < p_r_factors_size; ++ i) {
227 // Get the sign of the polynomials
228 int sgn = lp_polynomial_sgn(p_r_factors[i], map->m);
229 if (sgn == 0) {
230 if (p_r_zero == NULL) {
231 p_r_zero = p_r_factors[i];
232 } else {
233 int cmp = lp_polynomial_cmp(p_r_factors[i], p_r_zero);
234 if (cmp < 0) {
235 p_r_zero = p_r_factors[i];
236 }
237 }
238 }
239 }
240 }
241
242 // If we have a 0 factor, we just add that one
243 if (p_r_zero != NULL) {
244 assert(!lp_polynomial_is_constant(p_r_zero));
245 assert(x == lp_polynomial_top_variable(p_r_zero));
246 lp_projection_map_add_if_not_there(map, p_r_zero);
247 }
248
249 // Add factors, if not zero, and delete them
250 for (i = 0; i < p_r_factors_size; ++i) {
251 if (p_r_zero == NULL && !lp_polynomial_is_constant(p_r_factors[i])) {
252 assert(x == lp_polynomial_top_variable(p_r_factors[i]));
253 lp_projection_map_add_if_not_there(map, p_r_factors[i]);
254 }
255 lp_polynomial_delete(p_r_factors[i]);
256 }
257
258 // Hash the inputs
259 lp_polynomial_hash_set_insert(&map->all_polynomials, p);
260 lp_polynomial_hash_set_insert(&map->all_polynomials, p_r);
261
262 // Remove other temps
263 free(p_r_factors);
264 free(p_r_factors_multiplicities);
265 lp_polynomial_delete(p_r);
266 }
267
268 static
269 const lp_variable_order_t* lp_projection_map_variable_cmp_order = 0;
270
lp_projection_map_variable_cmp(const void * x,const void * y)271 int lp_projection_map_variable_cmp(const void* x, const void* y) {
272 lp_variable_t x_var = *(lp_variable_t*)x;
273 lp_variable_t y_var = *(lp_variable_t*)y;
274 return lp_variable_order_cmp(lp_projection_map_variable_cmp_order, x_var, y_var);
275 }
276
lp_projection_map_order_vars(lp_projection_map_t * map)277 void lp_projection_map_order_vars(lp_projection_map_t* map) {
278 lp_variable_list_order(&map->all_vars, map->order);
279 lp_variable_list_order(&map->unprojected_vars, map->order);
280 }
281
lp_projection_map_pop_top_unprojected_var(lp_projection_map_t * map)282 lp_variable_t lp_projection_map_pop_top_unprojected_var(lp_projection_map_t* map) {
283 if (lp_variable_list_size(&map->unprojected_vars) > 0) {
284 // Sort all unprojected variable based on order
285 lp_variable_list_order(&map->unprojected_vars, map->order);
286 lp_variable_t top = lp_variable_list_top(&map->unprojected_vars);
287 lp_variable_list_pop(&map->unprojected_vars);
288 return top;
289 } else {
290 return lp_variable_null;
291 }
292 }
293
lp_projection_map_print(const lp_projection_map_t * map,FILE * out)294 int lp_projection_map_print(const lp_projection_map_t* map, FILE* out) {
295 int ret = 0;
296 size_t i = 0;
297 for (i = 0; i < map->all_vars.list_size; ++ i) {
298 lp_variable_t x = map->all_vars.list[i];
299 ret += fprintf(out, "%s : ", lp_variable_db_get_name(map->var_db, x));
300 int_hmap_pair_t* find = int_hmap_find((int_hmap_t*) &map->var_to_index_map, x);
301 assert(find != NULL);
302 const lp_polynomial_hash_set_t* x_set = map->data + find->val;
303 ret += lp_polynomial_hash_set_print(x_set, out);
304 ret += fprintf(out, "\n");
305 }
306 return ret;
307 }
308
lp_projection_map_mk_root_atom(lp_projection_map_t * map,lp_variable_t x,size_t root_index,const lp_polynomial_t * p,root_atom_rel_t r)309 term_t lp_projection_map_mk_root_atom(lp_projection_map_t* map, lp_variable_t x, size_t root_index, const lp_polynomial_t* p, root_atom_rel_t r) {
310 assert(lp_polynomial_top_variable(p) == x);
311 assert(lp_polynomial_lc_sgn(p) > 0);
312
313 term_t root_atom = NULL_TERM;
314 term_manager_t* tm = map->nra->ctx->tm;
315
316 size_t p_deg = lp_polynomial_degree(p);
317 if (p_deg == 1 && lp_polynomial_lc_is_constant(p)) {
318 // Linear
319 // x r root(ax + b)
320 // x r -b/a [ a is positive ]
321 // ax + b r 0
322
323 term_t p_term = lp_polynomial_to_yices_term(map->nra, p);
324
325 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::projection")) {
326 ctx_trace_printf(map->nra->ctx, "p_term = "); ctx_trace_term(map->nra->ctx, p_term);
327 }
328
329 switch (r) {
330 case ROOT_ATOM_LT:
331 root_atom = mk_arith_term_lt0(tm, p_term);
332 break;
333 case ROOT_ATOM_LEQ:
334 root_atom = mk_arith_term_leq0(tm, p_term);
335 break;
336 case ROOT_ATOM_EQ: {
337 root_atom = mk_arith_term_eq0(tm, p_term);
338 break;
339 }
340 case ROOT_ATOM_NEQ:
341 root_atom = mk_arith_term_neq0(tm, p_term);
342 break;
343 case ROOT_ATOM_GEQ:
344 root_atom = mk_arith_term_geq0(tm, p_term);
345 break;
346 case ROOT_ATOM_GT:
347 root_atom = mk_arith_term_gt0(tm, p_term);
348 break;
349 default:
350 assert(false);
351 }
352 } else {
353 // Regular root atom
354 variable_t x_var = nra_plugin_get_variable_from_lp_variable(map->nra, x);
355 term_t x_term = variable_db_get_term(map->nra->ctx->var_db, x_var);
356 term_t p_term = lp_polynomial_to_yices_term(map->nra, p);
357 root_atom = mk_arith_root_atom(tm, root_index, x_term, p_term, r);
358 }
359
360 assert(term_kind(tm->terms, root_atom) != CONSTANT_TERM);
361
362 return root_atom;
363 }
364
365 #ifndef NDEBUG
366 static
ensure_true(plugin_context_t * ctx,term_t literal)367 bool ensure_true(plugin_context_t* ctx, term_t literal) {
368 term_t atom = unsigned_term(literal);
369 variable_t atom_var = variable_db_get_variable_if_exists(ctx->var_db, atom);
370 bool ok = true;
371 if (atom_var != variable_null) {
372 if (trail_has_value(ctx->trail, atom_var)) {
373 const mcsat_value_t* atom_value = trail_get_value(ctx->trail, atom_var);
374 if (atom_value->type != VALUE_BOOLEAN) {
375 fprintf(stderr, "Value not Boolean\n");
376 ok = false;
377 } else if (atom_value->b == (literal != atom)){
378 fprintf(stderr, "Value is false (should be true)\n");
379 ok = false;
380 }
381 }
382 }
383 if (!ok) {
384 fprintf(stderr, "var = %d\n", atom_var);
385 }
386
387 return ok;
388 }
389
390 #endif
391
392 /**
393 * Compare two polynomials by degree. Otherwise, go for the leading coefficients
394 */
polynomial_cmp(const void * p1_void,const void * p2_void)395 int polynomial_cmp(const void* p1_void, const void* p2_void) {
396 const lp_polynomial_t* p1 = *((const lp_polynomial_t**) p1_void);
397 const lp_polynomial_t* p2 = *((const lp_polynomial_t**) p2_void);
398 return lp_polynomial_cmp(p1, p2);
399 }
400
401 /**
402 * Simplify 0-polynomials with the GCD.
403 */
gcd_simplify_zero(const lp_polynomial_context_t * ctx,lp_polynomial_t ** polys,size_t * size,const lp_assignment_t * m)404 void gcd_simplify_zero(const lp_polynomial_context_t* ctx, lp_polynomial_t** polys, size_t* size, const lp_assignment_t* m) {
405 // Temp for GCD computation
406 lp_polynomial_t* gcd = lp_polynomial_new(ctx);
407
408 uint32_t i, j, to_keep = 0;
409 for (i = 0; i < *size; ++ i) {
410 const lp_polynomial_t* p = polys[i];
411 if (lp_polynomial_sgn(p, m) == 0) {
412 for (j = 0; j < to_keep; ++ j) {
413 const lp_polynomial_t* q = polys[j];
414 if (lp_polynomial_sgn(q, m) == 0) {
415 lp_polynomial_gcd(gcd, p, q);
416 if (!lp_polynomial_is_constant(gcd)) {
417 lp_polynomial_swap(polys[j], gcd);
418 break;
419 }
420 }
421 }
422 if (j >= to_keep) {
423 // Didn't embed it in any previous ones, keep it
424 polys[to_keep++] = polys[i];
425 } else {
426 // Not keeping it, have to remove it
427 lp_polynomial_delete(polys[i]);
428 }
429 } else {
430 // Keep it, it's non-zero
431 polys[to_keep++] = polys[i];
432 }
433 }
434
435 // Resized
436 *size = to_keep;
437
438 // Delete temp
439 lp_polynomial_delete(gcd);
440 }
441
442 /**
443 * Isolate the roots of the projection polynomials of x. Then construct a cell
444 * assertions and add to out. Return the bound polynomials in x_cell_a_p and x_cell_b_p.
445 */
lp_projection_map_construct_cell(lp_projection_map_t * map,lp_variable_t x,ivector_t * out,const lp_polynomial_t ** x_cell_a_p,const lp_polynomial_t ** x_cell_b_p)446 void lp_projection_map_construct_cell(lp_projection_map_t* map, lp_variable_t x, ivector_t* out,
447 const lp_polynomial_t** x_cell_a_p,
448 const lp_polynomial_t** x_cell_b_p
449 ) {
450
451 plugin_context_t* ctx = map->nra->ctx;
452
453 // Get the set to make sign invariant
454 lp_polynomial_hash_set_t* x_set = lp_projection_map_get_set_of(map, x);
455 lp_polynomial_hash_set_close(x_set);
456
457 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
458 ctx_trace_printf(ctx, "x_set = "); lp_polynomial_hash_set_print(x_set, ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
459 }
460
461 // Simplify the polynomials based on gcd:
462 // * If two polynomials evaluate to 0, they should be mutually prime
463 // * We just check: if both 0 and gcd, then we keep the gcd reducing the size
464 gcd_simplify_zero(map->ctx, x_set->data, &x_set->size, map->m);
465
466 // Sort the polynomials by degree
467 qsort(x_set->data, x_set->size, sizeof(lp_polynomial_t*), polynomial_cmp);
468
469 // The cell we're constructing
470 lp_interval_t x_cell;
471 lp_interval_construct_full(&x_cell);
472
473 // Lower bound polynomial and root index
474 (*x_cell_a_p) = NULL;
475 size_t x_cell_a_root_index = 0;
476
477 // Upper bound polynomial and root index
478 (*x_cell_b_p) = NULL;
479 size_t x_cell_b_root_index = 0;
480
481 size_t p_i;
482 bool done = false;
483 for (p_i = 0; !done && p_i < x_set->size; ++ p_i) {
484
485 assert(x_cell.a_open && x_cell.b_open);
486
487 // Polynomial and it's degree
488 const lp_polynomial_t* p = x_set->data[p_i];
489 assert(lp_polynomial_top_variable(p) == x);
490 size_t p_deg = lp_polynomial_degree(p);
491
492 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
493 ctx_trace_printf(ctx, "x_cell = "); lp_interval_print(&x_cell, ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
494 ctx_trace_printf(ctx, "x_cell_a_p = "); if (*x_cell_a_p != NULL) lp_polynomial_print((*x_cell_a_p), ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
495 ctx_trace_printf(ctx, "x_cell_a_root_index = %zu\n", x_cell_a_root_index);
496 ctx_trace_printf(ctx, "x_cell_b_p = "); if (*x_cell_b_p != NULL) lp_polynomial_print((*x_cell_b_p), ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
497 ctx_trace_printf(ctx, "x_cell_b_root_index = %zu\n", x_cell_b_root_index);
498 ctx_trace_printf(ctx, "p = "); lp_polynomial_print(p, ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
499 ctx_trace_printf(ctx, "p_deg = %zu\n", p_deg);
500 }
501
502 // Isolate the roots
503 assert(p_deg > 0);
504 lp_value_t* p_roots = safe_malloc(sizeof(lp_value_t)*p_deg);
505 size_t p_roots_size = 0;
506 lp_polynomial_roots_isolate(p, map->m, p_roots, &p_roots_size);
507
508 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
509 ctx_trace_printf(ctx, "roots = ");
510 size_t p_roots_i;
511 for (p_roots_i = 0; p_roots_i < p_roots_size; ++ p_roots_i) {
512 if (p_roots_i) {
513 ctx_trace_printf(ctx, ", ");
514 }
515 lp_value_print(p_roots + p_roots_i, ctx_trace_out(ctx));
516 }
517 ctx_trace_printf(ctx, "\n");
518 }
519
520 // Binary search for the current value x_v
521 const lp_value_t* x_v = lp_assignment_get_value(map->m, x);
522 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
523 ctx_trace_printf(ctx, "x_v = ");
524 lp_value_print(x_v, ctx_trace_out(ctx));
525 ctx_trace_printf(ctx, "\n");
526 }
527 if (p_roots_size > 0) {
528 int m; // midpoint and where to insert
529 int m_cmp;
530 int lb = 0;
531 int ub = p_roots_size - 1;
532
533 for(;;) {
534 m = (lb + ub) / 2;
535 m_cmp = lp_value_cmp(p_roots + m, x_v);
536
537 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
538 ctx_trace_printf(ctx, "m = %d\n", m);
539 ctx_trace_printf(ctx, "m_cmp = %d\n", m_cmp);
540 ctx_trace_printf(ctx, "lb = %d\n", lb);
541 ctx_trace_printf(ctx, "ub = %d\n", ub);
542 }
543
544 if (m_cmp == 0) {
545 // found
546 break;
547 } else if (m_cmp < 0) {
548 lb = m + 1;
549 if (lb > ub) {
550 // it's in m, m+1
551 break;
552 }
553 } else {
554 ub = m - 1;
555 if (lb > ub) {
556 // it's in m-1, m
557 m --;
558 break;
559 }
560 }
561 }
562
563 if (m_cmp == 0) {
564 // found it at m, so we take [roots[m], roots[m]] as the final one
565 // no need for more cell division
566 lp_interval_collapse_to(&x_cell, x_v);
567 (*x_cell_a_p) = p;
568 (*x_cell_b_p) = NULL;
569 x_cell_a_root_index = m;
570 // We use the first one, sort should do it
571 done = true;
572 } else {
573 // Divide cells
574 if (m < 0) {
575 // in (-inf, p_roots[0]) so
576 if (lp_interval_contains(&x_cell, p_roots)) {
577 lp_interval_set_b(&x_cell, p_roots, 1);
578 (*x_cell_b_p) = p;
579 x_cell_b_root_index = 0;
580 }
581 } else if (m + 1 == p_roots_size) {
582 // in (p_roots[m], +inf)
583 if (lp_interval_contains(&x_cell, p_roots + m)) {
584 lp_interval_set_a(&x_cell, p_roots + m, 1);
585 (*x_cell_a_p) = p;
586 x_cell_a_root_index = m;
587 }
588 } else {
589 // in (p_roots[m], p_roots[m+1])
590 if (lp_interval_contains(&x_cell, p_roots + m)) {
591 lp_interval_set_a(&x_cell, p_roots + m, 1);
592 (*x_cell_a_p) = p;
593 x_cell_a_root_index = m;
594 }
595 if (lp_interval_contains(&x_cell, p_roots + m + 1)) {
596 lp_interval_set_b(&x_cell, p_roots + m + 1, 1);
597 (*x_cell_b_p) = p;
598 x_cell_b_root_index = m + 1;
599 }
600 }
601 }
602 }
603
604 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
605 ctx_trace_printf(ctx, "roots = ");
606 size_t p_roots_i;
607 for (p_roots_i = 0; p_roots_i < p_roots_size; ++ p_roots_i) {
608 if (p_roots_i) {
609 ctx_trace_printf(ctx, ", ");
610 }
611 lp_value_print(p_roots + p_roots_i, ctx_trace_out(ctx));
612 }
613 ctx_trace_printf(ctx, "\n");
614 }
615
616 // Remove the roots
617 size_t p_roots_i;
618 for (p_roots_i = 0; p_roots_i < p_roots_size; ++ p_roots_i) {
619 lp_value_destruct(p_roots + p_roots_i);
620 }
621 safe_free(p_roots);
622 }
623
624 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
625 ctx_trace_printf(ctx, "x_cell = "); lp_interval_print(&x_cell, ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
626 ctx_trace_printf(ctx, "x_cell_a_p = "); if (*x_cell_a_p != NULL) lp_polynomial_print((*x_cell_a_p), ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
627 ctx_trace_printf(ctx, "x_cell_a_root_index = %zu\n", x_cell_a_root_index);
628 ctx_trace_printf(ctx, "x_cell_b_p = "); if (*x_cell_b_p != NULL) lp_polynomial_print((*x_cell_b_p), ctx_trace_out(ctx)); ctx_trace_printf(ctx, "\n");
629 ctx_trace_printf(ctx, "x_cell_b_root_index = %zu\n", x_cell_b_root_index);
630 }
631
632 // Add the cell constraint
633 if (lp_interval_is_point(&x_cell)) {
634 term_t eq_root_atom = lp_projection_map_mk_root_atom(map, x, x_cell_a_root_index, (*x_cell_a_p), ROOT_ATOM_EQ);
635 ivector_push(out, eq_root_atom);
636 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
637 ctx_trace_printf(ctx, "eq_root_atom = "); ctx_trace_term(ctx, eq_root_atom);
638 }
639 assert(ensure_true(ctx, eq_root_atom));
640 } else {
641
642 const lp_value_t* x_cell_lb = lp_interval_get_lower_bound(&x_cell);
643 const lp_value_t* x_cell_ub = lp_interval_get_upper_bound(&x_cell);
644
645 assert(lp_value_cmp(x_cell_lb, x_cell_ub) < 0);
646
647 if (x_cell_lb->type != LP_VALUE_MINUS_INFINITY) {
648 term_t lb_root_atom = lp_projection_map_mk_root_atom(map, x, x_cell_a_root_index, (*x_cell_a_p), ROOT_ATOM_GT);
649 ivector_push(out, lb_root_atom);
650 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
651 ctx_trace_printf(ctx, "lb_root_atom = "); ctx_trace_term(ctx, lb_root_atom);
652 }
653 assert(ensure_true(ctx, lb_root_atom));
654 }
655 if (x_cell_ub->type != LP_VALUE_PLUS_INFINITY) {
656 term_t ub_root_atom = lp_projection_map_mk_root_atom(map, x, x_cell_b_root_index, (*x_cell_b_p), ROOT_ATOM_LT);
657 ivector_push(out, ub_root_atom);
658 if (ctx_trace_enabled(ctx, "nra::explain::projection")) {
659 ctx_trace_printf(ctx, "ub_root_atom = "); ctx_trace_term(ctx, ub_root_atom);
660 }
661 assert(ensure_true(ctx, ub_root_atom));
662 }
663 }
664
665 // Destruct the cell
666 lp_interval_destruct(&x_cell);
667 }
668
669 /** Add the model based PSC of the two polynomials to the projection map */
lp_projection_map_add_psc(lp_projection_map_t * map,lp_polynomial_t *** polynomial_buffer,uint32_t * polynomial_buffer_size,lp_variable_t x,const lp_polynomial_t * p,const lp_polynomial_t * q)670 void lp_projection_map_add_psc(lp_projection_map_t* map, lp_polynomial_t*** polynomial_buffer, uint32_t* polynomial_buffer_size, lp_variable_t x, const lp_polynomial_t* p, const lp_polynomial_t* q) {
671 // Ensure buffer size min(deg(p_r_d), deg(p_r)) + 1 = p_r_deg
672 assert(lp_polynomial_top_variable(p) == x);
673 assert(lp_polynomial_top_variable(q) == x);
674
675 size_t p_deg = lp_polynomial_degree(p);
676 size_t q_deg = lp_polynomial_degree(q);
677
678 uint32_t psc_size = p_deg > q_deg ? q_deg + 1 : p_deg + 1;
679 polynomial_buffer_ensure_size(polynomial_buffer, polynomial_buffer_size, psc_size, map->ctx);
680
681 // Get the psc
682 lp_polynomial_psc(*polynomial_buffer, p, q);
683 // Add the initial sequence of the psc
684 uint32_t psc_i;
685 for (psc_i = 0; psc_i < psc_size; ++ psc_i) {
686 // Add it
687 lp_projection_map_add(map, (*polynomial_buffer)[psc_i]);
688 // If it doesn't vanish we're done
689 if (lp_polynomial_sgn((*polynomial_buffer)[psc_i], map->m)) {
690 break;
691 }
692 }
693 }
694
695 /** Add the model-based gcd of the two polynomials to the projection map */
lp_projection_map_add_mgcd(lp_projection_map_t * map,lp_variable_t x,const lp_polynomial_t * p,const lp_polynomial_t * q)696 void lp_projection_map_add_mgcd(lp_projection_map_t* map, lp_variable_t x, const lp_polynomial_t* p, const lp_polynomial_t* q) {
697 // Ensure buffer size min(deg(p_r_d), deg(p_r)) + 1 = p_r_deg
698 assert(lp_polynomial_top_variable(p) == x);
699 assert(lp_polynomial_top_variable(q) == x);
700
701 // Compute the gcd
702 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::mgcd")) {
703 ctx_trace_printf(map->nra->ctx, "p = "); lp_polynomial_print(p, ctx_trace_out(map->nra->ctx)); ctx_trace_printf(map->nra->ctx, "\n");
704 ctx_trace_printf(map->nra->ctx, "q = "); lp_polynomial_print(q, ctx_trace_out(map->nra->ctx)); ctx_trace_printf(map->nra->ctx, "\n");
705
706 lp_variable_list_t vars;
707 lp_variable_list_construct(&vars);
708 lp_polynomial_get_variables(p, &vars);
709 lp_polynomial_get_variables(q, &vars);
710 lp_variable_list_order(&vars, map->nra->lp_data.lp_var_order);
711
712 uint32_t i;
713 for (i = 0; i < vars.list_size; ++ i) {
714 lp_variable_t var = vars.list[i];
715 const lp_value_t* v = lp_assignment_get_value(map->m, var);
716 if (v->type != LP_VALUE_NONE) {
717 ctx_trace_printf(map->nra->ctx, "%s -> ", lp_variable_db_get_name(map->nra->lp_data.lp_var_db, var));
718 lp_value_print(v, ctx_trace_out(map->nra->ctx));
719 ctx_trace_printf(map->nra->ctx, "\n");
720 }
721 }
722
723 lp_variable_list_destruct(&vars);
724 }
725
726 lp_polynomial_vector_t* assumptions = lp_polynomial_mgcd(p, q, map->m);
727
728 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::mgcd")) {
729 ctx_trace_printf(map->nra->ctx, "mgcd done: \n");
730 }
731
732 // Add the initial sequence of the psc
733 uint32_t assumptions_i;
734 uint32_t assumptions_size = lp_polynomial_vector_size(assumptions);
735 for (assumptions_i = 0; assumptions_i < assumptions_size; ++ assumptions_i) {
736 // Add it
737 lp_polynomial_t* assumption = lp_polynomial_vector_at(assumptions, assumptions_i);
738 lp_projection_map_add(map, assumption);
739 lp_polynomial_delete(assumption);
740 }
741
742 lp_polynomial_vector_delete(assumptions);
743 }
744
lp_projection_map_reduce(lp_projection_map_t * map,lp_variable_t x,const lp_polynomial_t * p,lp_polynomial_t * p_r)745 void lp_projection_map_reduce(lp_projection_map_t* map, lp_variable_t x, const lp_polynomial_t* p, lp_polynomial_t* p_r) {
746
747 assert(p != p_r);
748 assert(lp_polynomial_top_variable(p) == x);
749
750 lp_polynomial_t* p_coeff = lp_polynomial_new(map->ctx);
751
752 uint32_t p_deg = lp_polynomial_degree(p);
753
754 lp_polynomial_reductum_m(p_r, p, map->m);
755 uint32_t p_r_deg = lp_polynomial_top_variable(p_r) == x ? lp_polynomial_degree(p_r) : 0;
756
757 // Add the vanishing initial coefficients (this includes the top reduced, hence the content)
758 uint32_t deg;
759 for (deg = p_r_deg; deg <= p_deg; ++ deg) {
760 // Add the coefficient
761 lp_polynomial_get_coefficient(p_coeff, p, deg);
762 lp_projection_map_add(map, p_coeff);
763 }
764
765 // Get the primitive part
766 lp_polynomial_pp(p_r, p_r);
767
768 lp_polynomial_delete(p_coeff);
769 }
770
771 /**
772 * Project the content of the map downwards until done. All the projection
773 * sets will be closed, so that iteration is possible.
774 */
lp_projection_map_project(lp_projection_map_t * map,ivector_t * out)775 void lp_projection_map_project(lp_projection_map_t* map, ivector_t* out) {
776
777 // Temps
778 const lp_polynomial_t* p = 0;
779 const lp_polynomial_t* q = 0;
780 lp_polynomial_t* p_r = lp_polynomial_new(map->ctx);
781 lp_polynomial_t* q_r = lp_polynomial_new(map->ctx);
782 lp_polynomial_t* p_r_d = lp_polynomial_new(map->ctx);
783
784 // PSC buffer
785 lp_polynomial_t** polynomial_buffer = 0;
786 uint32_t polynomial_buffer_size = 0;
787
788 const lp_polynomial_t* x_cell_a_p = NULL;
789 const lp_polynomial_t* x_cell_b_p = NULL;
790 lp_polynomial_t* x_cell_a_p_r = lp_polynomial_new(map->ctx);
791 lp_polynomial_t* x_cell_b_p_r = lp_polynomial_new(map->ctx);
792
793 // Project
794 for (;;) {
795
796 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::projection")) {
797 ctx_trace_printf(map->nra->ctx, "current projection:\n");
798 lp_projection_map_print(map, ctx_trace_out(map->nra->ctx));
799 }
800
801 // Get the top variable not projected yet
802 lp_variable_t x = lp_projection_map_pop_top_unprojected_var(map);
803 // If all projected, we're done
804 if (x == lp_variable_null) {
805 break;
806 }
807
808 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::projection")) {
809 ctx_trace_printf(map->nra->ctx, "x = %s\n", lp_variable_db_get_name(map->var_db, x));
810 }
811
812 // Get the set of polynomials to project
813 lp_polynomial_hash_set_close(lp_projection_map_get_set_of(map, x)); // We don't add again
814
815 // If we are at the top variable we project all polynomials.
816 // At the lower levels we:
817 // * Isolate the roots, find the two (or one) roots that enclose the current
818 // model (the cell, polynomials l, u).
819 // * L: polynomials that have roots below the cell
820 // * U: polynomials that have roots above the cell
821 // * The projection is then
822 // - all p: fix degree, and number of roots, i.e. red(p), and psc/gcd(p,p')
823 // - relationship between p in L, and l
824 // - relationship between p in U, and u
825 // - relationship between l and u
826 bool top = lp_assignment_get_value(map->m, x)->type == LP_VALUE_NONE;
827
828 if (!top) {
829 // Generate the cell, and get the bounding polynomials
830 x_cell_a_p = NULL;
831 x_cell_b_p = NULL;
832 lp_projection_map_construct_cell(map, x, out, &x_cell_a_p, &x_cell_b_p);
833 // Reduce the polynomials
834 if (x_cell_a_p != NULL) {
835 lp_projection_map_reduce(map, x, x_cell_a_p, x_cell_a_p_r);
836 }
837 if (x_cell_b_p != NULL) {
838 lp_projection_map_reduce(map, x, x_cell_b_p, x_cell_b_p_r);
839 }
840 }
841
842 // Go through the polynomials and project
843 uint32_t x_set_i;
844 for (x_set_i = 0; x_set_i < lp_projection_map_get_set_of(map, x)->size; ++ x_set_i) {
845
846 // Current polynomial
847 p = lp_projection_map_get_set_of(map, x)->data[x_set_i];
848 assert(lp_polynomial_top_variable(p) == x);
849 uint32_t p_deg = lp_polynomial_degree(p);
850
851 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::projection")) {
852 ctx_trace_printf(map->nra->ctx, "p = "); lp_polynomial_print(p, ctx_trace_out(map->nra->ctx)); ctx_trace_printf(map->nra->ctx, "\n");
853 ctx_trace_printf(map->nra->ctx, "p_deg = %u\n", p_deg);
854 }
855
856 // Reduce p modulo the model, and add assumptions
857 lp_projection_map_reduce(map, x, p, p_r);
858 uint32_t p_r_deg = lp_polynomial_top_variable(p_r) == x ? lp_polynomial_degree(p_r) : 0;
859
860 // Is p_r univariate?
861 bool p_r_univariate = lp_polynomial_is_univariate(p_r);
862
863 // Add the vanishing psc of p_r, p_r' (don't do univariate, they go to constants)
864 if (p_r_deg > 1 && !p_r_univariate) {
865 // Get the derivative
866 lp_polynomial_derivative(p_r_d, p_r);
867 // p_r is reduced, but the derivative might not be (the numberical constants)
868 lp_polynomial_pp(p_r_d, p_r_d);
869 // Add the projection
870 if (map->nra->ctx->options->nra_mgcd) {
871 lp_projection_map_add_mgcd(map, x, p_r, p_r_d);
872 } else {
873 lp_projection_map_add_psc(map, &polynomial_buffer, &polynomial_buffer_size, x, p_r, p_r_d);
874 }
875 }
876
877 if (p_r_deg > 0) {
878 // Now combine with other reductums
879 if (!map->nra->ctx->options->nra_nlsat && !top) {
880 // Compare with lower bound polynomial
881 if (p != x_cell_a_p && x_cell_b_p_r != NULL) {
882 uint32_t x_cell_a_p_deg = lp_polynomial_top_variable(x_cell_a_p_r) == x ? lp_polynomial_degree(x_cell_a_p_r) : 0;
883 if ((!p_r_univariate || !lp_polynomial_is_univariate(x_cell_a_p_r)) && x_cell_a_p_deg > 0) {
884 // Add the psc
885 if (map->nra->ctx->options->nra_mgcd) {
886 lp_projection_map_add_mgcd(map, x, p_r, x_cell_a_p_r);
887 } else {
888 lp_projection_map_add_psc(map, &polynomial_buffer, &polynomial_buffer_size, x, p_r, x_cell_a_p_r);
889 }
890 }
891 }
892 // Compare with upper bound polynomial
893 if (p != x_cell_b_p_r && x_cell_b_p_r != NULL) {
894 uint32_t x_cell_b_p_r_deg = lp_polynomial_top_variable(x_cell_b_p_r) == x ? lp_polynomial_degree(x_cell_b_p_r) : 0;
895 if ((!p_r_univariate || !lp_polynomial_is_univariate(x_cell_b_p_r)) && x_cell_b_p_r_deg > 0) {
896 // Add the psc
897 if (map->nra->ctx->options->nra_mgcd) {
898 lp_projection_map_add_mgcd(map, x, p_r, x_cell_b_p_r);
899 } else {
900 lp_projection_map_add_psc(map, &polynomial_buffer, &polynomial_buffer_size, x, p_r, x_cell_b_p_r);
901 }
902 }
903 }
904 } else {
905 // Top level, project with all
906 uint32_t x_set_j;
907 for (x_set_j = x_set_i + 1; x_set_j < lp_projection_map_get_set_of(map, x)->size; ++ x_set_j) {
908
909 // The other polynomial
910 q = lp_projection_map_get_set_of(map, x)->data[x_set_j];
911 assert(lp_polynomial_top_variable(p) == x);
912
913 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::projection")) {
914 ctx_trace_printf(map->nra->ctx, "q = "); lp_polynomial_print(q, ctx_trace_out(map->nra->ctx)); ctx_trace_printf(map->nra->ctx, "\n");
915 }
916
917 // Reductum
918 lp_polynomial_reductum_m(q_r, q, map->m);
919 uint32_t q_r_deg = lp_polynomial_top_variable(q_r) == x ? lp_polynomial_degree(q_r) : 0;
920
921 // No need to work on univariate ones
922 if (p_r_univariate && lp_polynomial_is_univariate(q_r)) {
923 continue;
924 }
925
926 if (ctx_trace_enabled(map->nra->ctx, "nra::explain::projection")) {
927 ctx_trace_printf(map->nra->ctx, "q_r = "); lp_polynomial_print(q_r, ctx_trace_out(map->nra->ctx)); ctx_trace_printf(map->nra->ctx, "\n");
928 ctx_trace_printf(map->nra->ctx, "q_r_deg = %u\n", q_r_deg);
929 }
930
931 if (q_r_deg > 0) {
932 // Add the psc
933 if (map->nra->ctx->options->nra_mgcd) {
934 lp_projection_map_add_mgcd(map, x, p_r, q_r);
935 } else {
936 lp_projection_map_add_psc(map, &polynomial_buffer, &polynomial_buffer_size, x, p_r, q_r);
937 }
938 }
939 }
940 }
941 }
942 }
943 }
944
945 // Free the temps
946 lp_polynomial_delete(p_r);
947 lp_polynomial_delete(q_r);
948 lp_polynomial_delete(p_r_d);
949 if (x_cell_a_p_r != NULL) {
950 lp_polynomial_delete(x_cell_a_p_r);
951 }
952 if (x_cell_b_p_r != NULL) {
953 lp_polynomial_delete(x_cell_b_p_r);
954 }
955 psc_buffer_delete(polynomial_buffer, polynomial_buffer_size);
956 }
957
958 #ifndef NDEBUG
959 static
constraint_has_value(const mcsat_trail_t * trail,const int_mset_t * pos,const int_mset_t * neg,variable_t constraint)960 bool constraint_has_value(const mcsat_trail_t* trail, const int_mset_t* pos, const int_mset_t* neg, variable_t constraint) {
961 if (trail_has_value(trail, constraint)) {
962 return true;
963 }
964 if (int_mset_contains(pos, constraint)) {
965 return true;
966 }
967 if (int_mset_contains(neg, constraint)) {
968 return true;
969 }
970 return false;
971 }
972 #endif
973
974 static
constraint_get_value(const mcsat_trail_t * trail,const int_mset_t * pos,const int_mset_t * neg,variable_t constraint)975 bool constraint_get_value(const mcsat_trail_t* trail, const int_mset_t* pos, const int_mset_t* neg, variable_t constraint) {
976 if (trail_has_value(trail, constraint)) {
977 return trail_get_boolean_value(trail, constraint);
978 }
979 if (int_mset_contains(pos, constraint)) {
980 return true;
981 }
982 if (int_mset_contains(neg, constraint)) {
983 return false;
984 }
985 assert(false);
986 return false;
987 }
988
nra_plugin_explain_conflict(nra_plugin_t * nra,const int_mset_t * pos,const int_mset_t * neg,const ivector_t * core,const ivector_t * lemma_reasons,ivector_t * conflict)989 void nra_plugin_explain_conflict(nra_plugin_t* nra, const int_mset_t* pos, const int_mset_t* neg,
990 const ivector_t* core, const ivector_t* lemma_reasons, ivector_t* conflict) {
991
992 if (ctx_trace_enabled(nra->ctx, "nra::explain")) {
993 ctx_trace_printf(nra->ctx, "nra_plugin_explain_conflict()\n");
994 uint32_t i;
995 int_mset_t variables;
996 int_mset_construct(&variables, variable_null);
997 for (i = 0; i < core->size; ++ i) {
998 term_t core_i_t = variable_db_get_term(nra->ctx->var_db, core->data[i]);
999 nra_plugin_get_constraint_variables(nra, core_i_t, &variables);
1000 ctx_trace_printf(nra->ctx, "core[%u] = ", i);
1001 ctx_trace_term(nra->ctx, core_i_t);
1002 }
1003 ivector_t* variables_list = int_mset_get_list(&variables);
1004 for (i = 0; i < variables_list->size; ++ i) {
1005 variable_t var = variables_list->data[i];
1006 if (trail_has_value(nra->ctx->trail, var)) {
1007 const mcsat_value_t* v = trail_get_value(nra->ctx->trail, var);
1008 variable_db_print_variable(nra->ctx->var_db, var, ctx_trace_out(nra->ctx));
1009 ctx_trace_printf(nra->ctx, " -> ");
1010 mcsat_value_print(v, ctx_trace_out(nra->ctx));
1011 ctx_trace_printf(nra->ctx, "\n");
1012 }
1013 }
1014 int_mset_destruct(&variables);
1015 }
1016
1017 // Create the map from variables to
1018 lp_projection_map_t projection_map;
1019 lp_projection_map_construct(&projection_map, nra);
1020
1021 // Add all the polynomials
1022 uint32_t core_i;
1023 for (core_i = 0; core_i < core->size; ++ core_i) {
1024 variable_t constraint_var = core->data[core_i];
1025 assert(constraint_has_value(nra->ctx->trail, pos, neg, constraint_var));
1026 const poly_constraint_t* constraint = poly_constraint_db_get(nra->constraint_db, constraint_var);
1027 const lp_polynomial_t* p = poly_constraint_get_polynomial(constraint);
1028 lp_projection_map_add(&projection_map, p);
1029 }
1030
1031 // Add all the top-level reasons for the conflict variable
1032 uint32_t lemma_reasons_i;
1033 for (lemma_reasons_i = 0; lemma_reasons_i < lemma_reasons->size; ++ lemma_reasons_i) {
1034 variable_t constraint_var = lemma_reasons->data[lemma_reasons_i];
1035 const poly_constraint_t* constraint = poly_constraint_db_get(nra->constraint_db, constraint_var);
1036 const lp_polynomial_t* p = poly_constraint_get_polynomial(constraint);
1037 lp_projection_map_add(&projection_map, p);
1038 }
1039
1040 // Project
1041 lp_projection_map_project(&projection_map, conflict);
1042
1043 // Add the core to the conflict
1044 for (core_i = 0; core_i < core->size; ++ core_i) {
1045 variable_t constraint_var = core->data[core_i];
1046 term_t constraint_term = variable_db_get_term(nra->ctx->var_db, constraint_var);
1047 assert(constraint_has_value(nra->ctx->trail, pos, neg, constraint_var));
1048 bool constraint_value = constraint_get_value(nra->ctx->trail, pos, neg, constraint_var);
1049 if (!constraint_value) {
1050 constraint_term = opposite_term(constraint_term);
1051 }
1052 ivector_push(conflict, constraint_term);
1053 }
1054
1055 // Remove the projection map
1056 lp_projection_map_destruct(&projection_map);
1057 }
1058