Skip to content

Commit 09e15e6

Browse files
author
Joe Hendrix
committed
Bugfixes to mcarith
1 parent e5bf7c1 commit 09e15e6

File tree

2 files changed

+156
-31
lines changed

2 files changed

+156
-31
lines changed

src/context/context.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5360,7 +5360,7 @@ static void create_mcarith_solver(context_t *ctx) {
53605360

53615361
// row saving must be enabled unless we're in ONECHECK mode
53625362
if (ctx->mode != CTX_MODE_ONECHECK) {
5363-
simplex_enable_row_saving(solver);
5363+
mcarith_enable_row_saving(solver);
53645364
}
53655365

53665366
if (ctx->egraph != NULL) {

src/solvers/mcarith/mcarith.c

Lines changed: 155 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,29 @@ void mcarith_check_atom_size(mcarith_solver_t *solver) {
429429
static
430430
void rba_buffer_add_mono_mcarithvar(mcarith_solver_t* solver, rba_buffer_t* b, rational_t *a, thvar_t v);
431431

432+
/**
433+
* This creates a term from a polynomial while taking care not to
434+
* introduce a polynomial from a constant.
435+
*/
436+
static
437+
term_t mcarith_poly(term_table_t* terms, rba_buffer_t* b) {
438+
439+
if (b->nterms == 0) {
440+
rational_t q;
441+
q_init(&q);
442+
return arith_constant(terms, &q);
443+
}
444+
445+
if (b->nterms == 1) {
446+
mono_t* m = b->mono + b->root;
447+
if (m->prod == empty_pp) {
448+
return arith_constant(terms, &m->coeff);
449+
}
450+
}
451+
452+
return arith_poly(terms, b);
453+
}
454+
432455
static
433456
term_t get_term(mcarith_solver_t* solver, thvar_t v) {
434457
arith_vartable_t* table;
@@ -469,7 +492,7 @@ term_t get_term(mcarith_solver_t* solver, thvar_t v) {
469492
rba_buffer_add_mono_mcarithvar(solver, &b, r, v);
470493
}
471494
}
472-
t = arith_poly(terms, &b);
495+
t = mcarith_poly(terms, &b);
473496
}
474497
break;
475498
case AVARTAG_KIND_PPROD:
@@ -648,8 +671,6 @@ term_t get_atom(mcarith_solver_t* solver, int32_t atom_index) {
648671
term_t v;
649672
rational_t* bnd;
650673
rba_buffer_t b;
651-
term_t polyTerm;
652-
653674

654675
mcarith_check_atom_size(solver);
655676

@@ -671,26 +692,31 @@ term_t get_atom(mcarith_solver_t* solver, int32_t atom_index) {
671692
// Assert v-b >= 0
672693
case GE_ATM: {
673694
if (q_is_zero(bnd)) {
674-
polyTerm = get_term(solver, var_of_atom(ap));
695+
term_t polyTerm;
696+
polyTerm = get_term(solver, v);
697+
result = arith_geq_atom(terms, polyTerm);
675698
} else {
699+
term_t polyTerm;
676700
// Create buffer b = v - bnd
677701
init_rba_buffer(&b, mcarith_solver_pprods(solver));
678702
rba_buffer_add_mcarithvar(solver, &b, v);
679703
rba_buffer_sub_const(&b, bnd);
680704
// Create term and free buffer.
681-
polyTerm = arith_poly(terms, &b);
705+
polyTerm = mcarith_poly(terms, &b);
682706
delete_rba_buffer(&b);
707+
result = arith_geq_atom(terms, polyTerm);
683708
}
684-
result = arith_geq_atom(terms, polyTerm);
685709
break;
686710
}
687711
// Assert v <= b by asserting b-v >= 0
688712
case LE_ATM: {
713+
term_t polyTerm;
714+
689715
// Create buffer b = bnd - v
690716
init_rba_buffer(&b, mcarith_solver_pprods(solver));
691717
rba_buffer_sub_mcarithvar(solver, &b, v);
692718
rba_buffer_add_const(&b, bnd);
693-
polyTerm = arith_poly(terms, &b);
719+
polyTerm = mcarith_poly(terms, &b);
694720
delete_rba_buffer(&b);
695721
result = arith_geq_atom(terms, polyTerm);
696722
break;
@@ -716,24 +742,30 @@ thvar_t mcarith_create_pprod(void *s, pprod_t *p, thvar_t *map) {
716742
assert(pprod_degree(p) > 1);
717743
assert(!pp_is_empty(p));
718744
assert(!pp_is_var(p));
719-
720745
// Create theory variable
721746
thvar_t v = simplex_create_var(&solver->simplex, false);
722747
// Remap variables in powerproduct
723748
mcarith_check_var_size(solver);
724749
pp_buffer_t b;
725750
init_pp_buffer(&b, p->len);
751+
uint32_t n = p->len;
752+
int32_t* vars = safe_malloc(sizeof(int32_t) * n);
753+
uint32_t* exps = safe_malloc(sizeof(uint32_t) * n);
754+
726755
for (uint32_t i = 0; i < p->len; ++i) {
727756
thvar_t mv = map[i];
728757
assert(mv < v);
729-
term_t t = get_term(solver, mv);
730-
pp_buffer_set_varexp(&b, t, p->prod[i].exp);
758+
vars[i] = get_term(solver, mv);
759+
exps[i] = p->prod[i].exp;
731760
}
732-
pp_buffer_normalize(&b);
761+
pp_buffer_set_varexps(&b, n, vars, exps);
762+
free(vars);
763+
free(exps);
733764

734-
// Create term
735765
assert(solver->var_terms_size > v);
736-
solver->var_terms[v] = pprod_term_from_buffer(mcarith_solver_terms(solver), &b);
766+
767+
term_t t = pprod_term_from_buffer(mcarith_solver_terms(solver), &b);
768+
solver->var_terms[v] = t;
737769
// Free buffer and return
738770
delete_pp_buffer(&b);
739771
return v;
@@ -839,6 +871,23 @@ void init_rba_buffer_from_poly(mcarith_solver_t* solver,
839871
}
840872
}
841873

874+
static
875+
bool rba_buffer_get_const(rba_buffer_t* b, rational_t* r) {
876+
if (b->nterms == 0) {
877+
q_init(r);
878+
return true;
879+
} else if (b->nterms == 1) {
880+
mono_t* m = b->mono + b->root;
881+
if (m->prod == empty_pp) {
882+
q_init(r);
883+
q_set(r, &m->coeff);
884+
return true;
885+
}
886+
}
887+
return false;
888+
}
889+
890+
842891
/*
843892
* Check for integer feasibility
844893
*/
@@ -847,21 +896,18 @@ fcheck_code_t mcarith_final_check(void* s) {
847896
mcarith_solver_t *solver;
848897
term_table_t* terms;
849898
uint32_t acnt;
850-
899+
term_t t;
851900

852901
solver = s;
853902
terms = mcarith_solver_terms(solver);
903+
assert(!solver->simplex.unsat_before_search);
854904

855-
yices_pp_t printer;
856-
pp_area_t area;
857-
858-
area.width = 72;
859-
area.height = 8;
860-
area.offset = 2;
861-
area.stretch = false;
862-
area.truncate = true;
905+
fcheck_code_t result;
863906

864-
init_default_yices_pp(&printer, stdout, &area);
907+
result = simplex_final_check(&solver->simplex);
908+
if (result == FCHECK_CONTINUE) {
909+
return result;
910+
}
865911

866912
mcarith_free_mcsat(solver);
867913

@@ -892,18 +938,40 @@ fcheck_code_t mcarith_final_check(void* s) {
892938
p = arith_eq_atom(terms, get_term(solver, a->def.var));
893939
break;
894940
case VAR_GE0:
895-
p = arith_geq_atom(terms, get_term(solver, a->def.var));
941+
t = get_term(solver, a->def.var);
942+
assert(term_kind(terms, t) != ARITH_CONSTANT);
943+
p = arith_geq_atom(terms, t);
896944
break;
897-
case POLY_EQ0:
945+
case POLY_EQ0: {
946+
rational_t br;
947+
898948
init_rba_buffer_from_poly(solver, &b, a->def.poly);
899-
p = arith_eq_atom(terms, arith_poly(terms, &b));
949+
if (rba_buffer_get_const(&b, &br)) {
950+
p = bool2term(q_is_zero(&br));
951+
q_clear(&br);
952+
} else {
953+
t = arith_poly(terms, &b);
954+
assert(term_kind(terms, t) != ARITH_CONSTANT);
955+
p = arith_eq_atom(terms, t);
956+
}
900957
delete_rba_buffer(&b);
901958
break;
902-
case POLY_GE0:
959+
}
960+
case POLY_GE0: {
961+
rational_t br;
962+
903963
init_rba_buffer_from_poly(solver, &b, a->def.poly);
904-
p = arith_geq_atom(terms, arith_poly(terms, &b));
964+
if (rba_buffer_get_const(&b, &br)) {
965+
p = bool2term(q_is_nonneg(&br));
966+
q_clear(&br);
967+
} else {
968+
t = arith_poly(terms, &b);
969+
assert(term_kind(terms, t) != ARITH_CONSTANT);
970+
p = arith_geq_atom(terms, t);
971+
}
905972
delete_rba_buffer(&b);
906973
break;
974+
}
907975
case ATOM_ASSERT:
908976
p = get_atom(solver, a->def.atom);
909977
break;
@@ -920,10 +988,9 @@ fcheck_code_t mcarith_final_check(void* s) {
920988
literals[literal_count] = end_clause;
921989

922990
int32_t r = mcsat_assert_formulas(solver->mcsat, acnt, assertions);
923-
fcheck_code_t result;
924991
if (r == TRIVIALLY_UNSAT) {
925992
record_theory_conflict(solver->simplex.core, literals);
926-
mcarith_free_mcsat(solver);
993+
mcarith_free_mcsat(solver);
927994
result = FCHECK_CONTINUE;
928995
} else if (r == CTX_NO_ERROR) {
929996
result = FCHECK_SAT;
@@ -990,7 +1057,10 @@ void mcarith_increase_decision_level(mcarith_solver_t *solver) {
9901057
void mcarith_backtrack(mcarith_solver_t *solver, uint32_t back_level) {
9911058
mcarith_undo_record_t* r = mcarith_undo_backtrack(&solver->undo_stack, back_level);
9921059
mcarith_backtrack_assertions(solver, r->n_assertions);
1060+
uint32_t vc = solver->simplex.vtbl.nvars;
9931061
simplex_backtrack(&solver->simplex, back_level);
1062+
uint32_t vc0 = solver->simplex.vtbl.nvars;
1063+
assert(vc == vc0);
9941064
}
9951065

9961066
/*
@@ -1028,7 +1098,10 @@ void mcarith_pop(mcarith_solver_t *solver) {
10281098
* Reset to the empty solver
10291099
*/
10301100
void mcarith_reset(mcarith_solver_t *solver) {
1101+
uint32_t vc = solver->simplex.vtbl.nvars;
10311102
simplex_reset(&solver->simplex);
1103+
uint32_t vc0 = solver->simplex.vtbl.nvars;
1104+
assert(vc == vc0); // FIXME
10321105

10331106
mcarith_undo_reset(&solver->undo_stack);
10341107
mcarith_backtrack_assertions(solver, 0);
@@ -1134,6 +1207,27 @@ thvar_t mcarith_create_poly(void* s, polynomial_t *p, thvar_t *map) {
11341207
return simplex_create_poly(&solver->simplex, p, map);
11351208
}
11361209

1210+
typedef struct{
1211+
uint32_t bstack_top;
1212+
uint32_t matrix_nrows;
1213+
} simplex_assertion_count_t;
1214+
1215+
static simplex_assertion_count_t simplex_assertion_count(simplex_solver_t* simplex) {
1216+
simplex_assertion_count_t r;
1217+
r.bstack_top = simplex->bstack.top;
1218+
r.matrix_nrows = simplex->matrix.nrows;
1219+
return r;
1220+
}
1221+
1222+
/**
1223+
* Returns true if the simplex solver concluded the assertion just added did not
1224+
* need to get recorded as it was true or false from previous assertions.
1225+
*/
1226+
static bool simplex_handled_assertion(simplex_solver_t* simplex, simplex_assertion_count_t c) {
1227+
return simplex->unsat_before_search
1228+
|| (simplex->matrix.nrows == c.matrix_nrows && simplex->bstack.top == c.bstack_top);
1229+
}
1230+
11371231
/*
11381232
* Assert a top-level equality constraint (either x == 0 or x != 0)
11391233
* - tt indicates whether the constraint or its negation must be asserted
@@ -1145,7 +1239,11 @@ static void mcarith_assert_eq_axiom(void* s, thvar_t x, bool tt) {
11451239
mcarith_assertion_t* assert;
11461240

11471241
solver = s;
1242+
// Get number of assertions
1243+
simplex_assertion_count_t cinit = simplex_assertion_count(&solver->simplex);
11481244
simplex_assert_eq_axiom(&solver->simplex, x, tt);
1245+
if (simplex_handled_assertion(&solver->simplex, cinit))
1246+
return;
11491247

11501248
// Record assertion for sending to mcarith solver.
11511249
assert = alloc_top_assertion(solver);
@@ -1166,7 +1264,11 @@ static void mcarith_assert_ge_axiom(void* s, thvar_t x, bool tt){
11661264
mcarith_assertion_t* assert;
11671265

11681266
solver = s;
1267+
// Get number of assertions
1268+
simplex_assertion_count_t cinit = simplex_assertion_count(&solver->simplex);
11691269
simplex_assert_ge_axiom(&solver->simplex, x, tt);
1270+
if (simplex_handled_assertion(&solver->simplex, cinit))
1271+
return;
11701272

11711273
assert = alloc_top_assertion(solver);
11721274
assert->type = VAR_GE0;
@@ -1188,10 +1290,15 @@ static void mcarith_assert_poly_eq_axiom(void * s, polynomial_t *p, thvar_t *map
11881290
solver = s;
11891291
assert(p->nterms > 0);
11901292

1293+
simplex_assertion_count_t cinit = simplex_assertion_count(&solver->simplex);
11911294
simplex_assert_poly_eq_axiom(&solver->simplex, p, map, tt);
1295+
if (simplex_handled_assertion(&solver->simplex, cinit))
1296+
return;
11921297

11931298
assert = alloc_top_assertion(solver);
11941299
assert->type = POLY_EQ0;
1300+
assert(p->nterms > 0);
1301+
assert(p->nterms > 1 || p->mono[0].var != const_idx);
11951302
assert->def.poly = alloc_polynomial_from_map(p, map, solver->simplex.vtbl.nvars);
11961303
assert->tt = tt;
11971304
assert->lit = null_literal;
@@ -1209,10 +1316,15 @@ static void mcarith_assert_poly_ge_axiom(void *s, polynomial_t *p, thvar_t *map,
12091316
solver = s;
12101317
assert(p->nterms > 0);
12111318

1319+
simplex_assertion_count_t cinit = simplex_assertion_count(&solver->simplex);
12121320
simplex_assert_poly_ge_axiom(&solver->simplex, p, map, tt);
1321+
if (simplex_handled_assertion(&solver->simplex, cinit))
1322+
return;
12131323

12141324
assert = alloc_top_assertion(solver);
12151325
assert->type = POLY_GE0;
1326+
assert(p->nterms > 0);
1327+
assert(p->nterms > 1 || p->mono[0].var != const_idx);
12161328
assert->def.poly = alloc_polynomial_from_map(p, map, solver->simplex.vtbl.nvars);
12171329
assert->tt = tt;
12181330
assert->lit = null_literal;
@@ -1228,7 +1340,10 @@ void mcarith_assert_vareq_axiom(void* s, thvar_t x, thvar_t y, bool tt) {
12281340
mcarith_assertion_t* assert;
12291341

12301342
solver = s;
1343+
simplex_assertion_count_t cinit = simplex_assertion_count(&solver->simplex);
12311344
simplex_assert_vareq_axiom(&solver->simplex, x, y, tt);
1345+
if (simplex_handled_assertion(&solver->simplex, cinit))
1346+
return;
12321347

12331348
assert = alloc_top_assertion(solver);
12341349
assert->type = VAR_EQ;
@@ -1245,7 +1360,12 @@ static
12451360
void mcarith_assert_cond_vareq_axiom(void* s, literal_t c, thvar_t x, thvar_t y) {
12461361
mcarith_solver_t *solver;
12471362
solver = s;
1363+
simplex_assertion_count_t cinit = simplex_assertion_count(&solver->simplex);
12481364
simplex_assert_cond_vareq_axiom(&solver->simplex, c, x, y);
1365+
if (simplex_handled_assertion(&solver->simplex, cinit))
1366+
return;
1367+
1368+
assert(false);
12491369
}
12501370

12511371
/*
@@ -1254,7 +1374,12 @@ void mcarith_assert_cond_vareq_axiom(void* s, literal_t c, thvar_t x, thvar_t y)
12541374
static
12551375
void mcarith_assert_clause_vareq_axiom(void* s, uint32_t n, literal_t *c, thvar_t x, thvar_t y) {
12561376
mcarith_solver_t *solver = s;
1377+
simplex_assertion_count_t cinit = simplex_assertion_count(&solver->simplex);
12571378
simplex_assert_clause_vareq_axiom(&solver->simplex, n, c, x, y);
1379+
if (simplex_handled_assertion(&solver->simplex, cinit))
1380+
return;
1381+
1382+
assert(false);
12581383
}
12591384

12601385
/*

0 commit comments

Comments
 (0)