3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-24 20:16:00 +00:00

arith updates

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2023-05-14 15:53:58 -07:00
parent 62e1ec0698
commit e5231c040d
20 changed files with 526 additions and 165 deletions

View file

@ -246,7 +246,7 @@ void smt_params::setup_QF_LRA(static_features const& st) {
m_phase_selection = PS_THEORY;
if (!st.m_cnf) {
m_restart_strategy = RS_GEOMETRIC;
m_arith_stronger_lemmas = false;
m_arith_relax_bounds = false;
m_restart_adaptive = false;
}
m_arith_small_lemma_size = 32;
@ -288,7 +288,7 @@ void smt_params::setup_QF_LIA(static_features const& st) {
}
if (st.m_num_bin_clauses + st.m_num_units == st.m_num_clauses && st.m_cnf && st.m_arith_k_sum > rational(100000)) {
m_arith_bound_prop = bound_prop_mode::BP_NONE;
m_arith_stronger_lemmas = false;
m_arith_relax_bounds = false;
}
}

View file

@ -52,7 +52,7 @@ void theory_arith_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_arith_blands_rule_threshold);
DISPLAY_PARAM(m_arith_propagate_eqs);
DISPLAY_PARAM((unsigned)m_arith_bound_prop);
DISPLAY_PARAM(m_arith_stronger_lemmas);
DISPLAY_PARAM(m_arith_relax_bounds);
DISPLAY_PARAM(m_arith_skip_rows_with_big_coeffs);
DISPLAY_PARAM(m_arith_max_lemma_size);
DISPLAY_PARAM(m_arith_small_lemma_size);

View file

@ -58,7 +58,7 @@ struct theory_arith_params {
unsigned m_arith_blands_rule_threshold = 1000;
bool m_arith_propagate_eqs = true;
bound_prop_mode m_arith_bound_prop = bound_prop_mode::BP_REFINE;
bool m_arith_stronger_lemmas = true;
bool m_arith_relax_bounds = true;
bool m_arith_skip_rows_with_big_coeffs = true;
unsigned m_arith_max_lemma_size = 128;
unsigned m_arith_small_lemma_size = 16;

View file

@ -43,7 +43,7 @@ namespace smt {
struct theory_arith_stats {
unsigned m_conflicts, m_add_rows, m_pivots, m_diseq_cs, m_gomory_cuts, m_branches, m_gcd_tests, m_gcd_conflicts, m_patches, m_patches_succ;
unsigned m_assert_lower, m_assert_upper, m_assert_diseq, m_core2th_eqs, m_core2th_diseqs;
unsigned m_th2core_eqs, m_th2core_diseqs, m_bound_props, m_offset_eqs, m_fixed_eqs, m_offline_eqs;
unsigned m_th2core_eqs, m_th2core_diseqs, m_bound_props, m_bound_axioms, m_offset_eqs, m_fixed_eqs, m_offline_eqs;
unsigned m_max_min;
unsigned m_assume_eqs;
unsigned m_gb_simplify, m_gb_superpose, m_gb_compute_basis, m_gb_num_processed;
@ -541,7 +541,7 @@ namespace smt {
double adaptive_assertion_threshold() const { return m_params.m_arith_adaptive_assertion_threshold; }
unsigned max_lemma_size() const { return m_params.m_arith_max_lemma_size; }
unsigned small_lemma_size() const { return m_params.m_arith_small_lemma_size; }
bool relax_bounds() const { return m_params.m_arith_stronger_lemmas; }
bool relax_bounds() const { return m_params.m_arith_relax_bounds; }
bool skip_big_coeffs() const { return m_params.m_arith_skip_rows_with_big_coeffs; }
bool process_atoms() const;
unsigned get_num_conflicts() const { return m_num_conflicts; }

View file

@ -2141,6 +2141,8 @@ namespace smt {
if (candidates.empty())
return;
verbose_stream() << "candidates " << candidates.size() << "\n";
m_tmp_var_set.reset();
m_tmp_var_set2.reset();
for (theory_var v : candidates) {

View file

@ -1148,6 +1148,7 @@ namespace smt {
mk_clause(~l1, l2, 3, coeffs);
}
}
++m_stats.m_bound_axioms;
}
template<typename Ext>
@ -1489,6 +1490,19 @@ namespace smt {
unsigned old_idx = m_final_check_idx;
final_check_status result = FC_DONE;
final_check_status ok;
//display(verbose_stream());
//exit(0);
if (false)
{
verbose_stream() << "final\n";
::statistics stats;
collect_statistics(stats);
stats.display(verbose_stream());
}
do {
if (ctx.get_cancel_flag()) {
return FC_GIVEUP;
@ -2812,10 +2826,11 @@ namespace smt {
template<typename Ext>
void theory_arith<Ext>::explain_bound(row const & r, int idx, bool is_lower, inf_numeral & delta, antecedents& ante) {
SASSERT(delta >= inf_numeral::zero());
TRACE("arith_conflict", tout << "relax: " << relax_bounds() << " lits: " << ante.lits().size() << " eqs: " << ante.eqs().size() << " idx: " << idx << "\n";);
if (!relax_bounds() && (!ante.lits().empty() || !ante.eqs().empty())) {
return;
}
row_entry const & entry = r[idx];
numeral coeff = entry.m_coeff;
if (relax_bounds()) {
@ -2835,6 +2850,7 @@ namespace smt {
if (!b->has_justification()) {
continue;
}
if (!relax_bounds() || delta.is_zero()) {
TRACE("propagate_bounds", tout << "push justification: v" << it->m_var << "\n";);
b->push_justification(ante, it->m_coeff, coeffs_enabled());

View file

@ -219,7 +219,7 @@ namespace smt {
{
std::function<expr*(void)> fn = [&]() { return m.mk_or(bound, m.mk_not(bound)); };
scoped_trace_stream _sts(*this, fn);
IF_VERBOSE(10, verbose_stream() << "branch " << bound << "\n");
IF_VERBOSE(4, verbose_stream() << "branch " << bound << "\n");
TRACE("arith_int", tout << mk_bounded_pp(bound, m) << "\n";);
ctx.internalize(bound, true);
ctx.mark_as_relevant(bound.get());
@ -670,13 +670,14 @@ namespace smt {
TRACE("gomory_cut", tout << "new cut:\n" << bound << "\n"; ante.display(tout););
literal l = null_literal;
context & ctx = get_context();
ctx.get_rewriter()(bound);
{
std::function<expr*(void)> fn = [&]() { return bound; };
scoped_trace_stream _sts(*this, fn);
ctx.internalize(bound, true);
}
l = ctx.get_literal(bound);
IF_VERBOSE(10, verbose_stream() << "cut " << bound << "\n");
IF_VERBOSE(4, verbose_stream() << "cut " << bound << "\n");
ctx.mark_as_relevant(l);
auto js = ctx.mk_justification(
gomory_cut_justification(
@ -906,6 +907,7 @@ namespace smt {
bool inf_l, inf_u;
inf_numeral l, u;
numeral m;
unsigned num_patched = 0, num_not_patched = 0;
for (theory_var v = 0; v < num; v++) {
if (!is_non_base(v))
continue;
@ -915,6 +917,7 @@ namespace smt {
// check whether value of v is already a multiple of m.
if ((get_value(v).get_rational() / m).is_int())
continue;
TRACE("patch_int",
tout << "TARGET v" << v << " -> [";
if (inf_l) tout << "-oo"; else tout << ceil(l);
@ -922,6 +925,15 @@ namespace smt {
if (inf_u) tout << "oo"; else tout << floor(u);
tout << "]";
tout << ", m: " << m << ", val: " << get_value(v) << ", is_int: " << is_int(v) << "\n";);
verbose_stream() << "TARGET v" << v << " -> [";
if (inf_l) verbose_stream() << "-oo"; else verbose_stream() << ceil(l);
verbose_stream() << ", ";
if (inf_u) verbose_stream() << "oo"; else verbose_stream() << floor(u);
verbose_stream() << "]";
verbose_stream() << ", m: " << m << ", val: " << get_value(v) << ", is_int: " << is_int(v) << "\n";
if (!inf_l)
l = ceil(l);
if (!inf_u)
@ -932,8 +944,11 @@ namespace smt {
if (!inf_u)
u = m*floor(u/m);
}
if (!inf_l && !inf_u && l > u)
if (!inf_l && !inf_u && l > u) {
++num_not_patched;
continue; // cannot patch
}
++num_patched;
if (!inf_l)
set_value(v, l);
else if (!inf_u)
@ -942,6 +957,7 @@ namespace smt {
set_value(v, inf_numeral(0));
}
SASSERT(m_to_patch.empty());
verbose_stream() << "patched " << num_patched << " not patched " << num_not_patched << "\n";
}
/**

View file

@ -33,13 +33,14 @@ namespace smt {
st.update("arith assert upper", m_stats.m_assert_upper);
st.update("arith assert diseq", m_stats.m_assert_diseq);
st.update("arith bound prop", m_stats.m_bound_props);
st.update("arith bound axioms", m_stats.m_bound_axioms);
st.update("arith fixed eqs", m_stats.m_fixed_eqs);
st.update("arith assume eqs", m_stats.m_assume_eqs);
st.update("arith offset eqs", m_stats.m_offset_eqs);
st.update("arith gcd tests", m_stats.m_gcd_tests);
st.update("arith gcd conflicts", m_stats.m_gcd_conflicts);
st.update("arith ineq splits", m_stats.m_branches);
st.update("arith gomory cuts", m_stats.m_gomory_cuts);
st.update("arith branch", m_stats.m_branches);
st.update("arith branch int", m_stats.m_branch_infeasible_int);
st.update("arith branch var", m_stats.m_branch_infeasible_var);
st.update("arith patches", m_stats.m_patches);

View file

@ -695,7 +695,7 @@ void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges
template<typename Ext>
void theory_diff_logic<Ext>::set_neg_cycle_conflict() {
m_nc_functor.reset();
m_graph.traverse_neg_cycle2(m_params.m_arith_stronger_lemmas, m_nc_functor);
m_graph.traverse_neg_cycle2(m_params.m_arith_relax_bounds, m_nc_functor);
inc_conflicts();
literal_vector const& lits = m_nc_functor.get_lits();
TRACE("arith_conflict",

View file

@ -127,6 +127,7 @@ class theory_lra::imp {
ptr_vector<expr>& to_ensure_enode() { return m_st.m_to_ensure_enode; }
ptr_vector<expr>& to_ensure_var() { return m_st.m_to_ensure_var; }
void push(expr* e, rational c) { m_st.m_terms.push_back(e); m_st.m_coeffs.push_back(c); }
void add(theory_var v, rational const& c) { vars().push_back(v); coeffs().push_back(c); }
void set_back(unsigned i) {
if (terms().size() == i + 1) return;
terms()[i] = terms().back();
@ -335,17 +336,204 @@ class theory_lra::imp {
}
bool internalize_term2(app* term) {
TRACE("arith_internalize", tout << "internalising term:\n" << mk_pp(term, m) << "\n";);
theory_var v = internalize_term_core(term);
TRACE("arith_internalize", tout << "theory_var: " << v << "\n";);
return v != null_theory_var;
}
theory_var internalize_add(app* n) {
TRACE("add_bug", tout << "n: " << mk_pp(n, m) << "\n";);
CTRACE("internalize_add_bug", n->get_num_args() == 2 && n->get_arg(0) == n->get_arg(1), tout << "n: " << mk_pp(n, m) << "\n";);
SASSERT(a.is_add(n));
scoped_internalize_state st(*this);
for (expr* arg : *n)
internalize_internal_monomial(to_app(arg), st);
enode* e = mk_enode(n);
theory_var v = e->get_th_var(get_id());
if (v == null_theory_var)
v = internalize_linearized_def(n, st);
return v;
}
void internalize_internal_monomial(app* arg, scoped_internalize_state& st) {
expr* arg1, * arg2;
rational val, val2;
if (ctx().e_internalized(arg)) {
enode* e = ctx().get_enode(arg);
if (th.is_attached_to_var(e)) {
// there is already a theory variable (i.e., name) for arg.
st.add(e->get_th_var(get_id()), rational::one());
return;
}
}
if (a.is_extended_numeral(arg, val))
st.add(internalize_numeral(arg, val), rational::one());
else if (a.is_mul(arg, arg1, arg2)) {
if (a.is_extended_numeral(arg2, val))
std::swap(arg1, arg2);
if (a.is_extended_numeral(arg1, val)) {
st.add(internalize_term_core(to_app(arg2)), val);
if (reflect(arg)) {
internalize_term_core(to_app(arg1));
mk_enode(arg);
}
return;
}
}
st.add(internalize_term_core(arg), rational::one());
}
theory_var internalize_numeral(app* n, rational const& val) {
if (ctx().e_internalized(n))
return mk_var(n);
enode* e = mk_enode(n);
theory_var v = mk_var(n);
lpvar vi = get_lpvar(v);
if (vi == UINT_MAX) {
vi = lp().add_var(v, a.is_int(n));
add_def_constraint_and_equality(vi, lp::GE, val);
add_def_constraint_and_equality(vi, lp::LE, val);
register_fixed_var(v, val);
}
return v;
}
/**
\brief Internalize the terms of the form (* c (* t1 ... tn)) and (* t1 ... tn).
Return an alias for the term.
*/
theory_var internalize_mul1(app* arg) {
rational val;
TRACE("arith", tout << arg->get_num_args() << " " << mk_pp(arg, m) << "\n";);
SASSERT(a.is_mul(arg));
expr* arg0 = arg->get_arg(0);
expr* arg1 = arg->get_arg(1);
if (a.is_numeral(arg1))
std::swap(arg0, arg1);
if (a.is_numeral(arg0, val) && !a.is_numeral(arg1) && arg->get_num_args() == 2) {
if (val.is_zero())
return internalize_numeral(arg, val);
scoped_internalize_state st(*this);
if (reflect(arg))
internalize_term_core(to_app(arg0));
st.add(internalize_mul_core(to_app(arg1)), val);
mk_enode(arg);
return internalize_linearized_def(arg, st);
}
else
return internalize_mul_core(arg);
}
theory_var internalize_mul_core(app* t) {
TRACE("internalize_mul_core", tout << "internalizing...\n" << mk_pp(t, m) << "\n";);
if (!a.is_mul(t))
return internalize_term_core(t);
for (expr* arg : *t) {
theory_var v = internalize_term_core(to_app(arg));
if (v == null_theory_var)
mk_var(to_app(arg));
}
enode* e = mk_enode(t);
theory_var v = e->get_th_var(get_id());
if (v == null_theory_var)
v = mk_var(t);
return v;
}
/**
* \brief Internalize the given term and return an alias for it.
* Return null_theory_var if the term was not implemented by the theory yet.
*/
theory_var internalize_term_core(app* n) {
TRACE("arith_internalize_detail", tout << "internalize_term_core:\n" << mk_pp(n, m) << "\n";);
if (ctx().e_internalized(n)) {
enode* e = ctx().get_enode(n);
if (th.is_attached_to_var(e))
return e->get_th_var(get_id());
}
SASSERT(!a.is_uminus(n));
rational val;
if (a.is_add(n))
return internalize_add(n);
else if (a.is_extended_numeral(n, val))
return internalize_numeral(n, val);
else if (a.is_mul(n))
return internalize_mul1(n);
else if (a.is_arith_expr(n))
NOT_IMPLEMENTED_YET();
#if 0
else if (a.is_div(n))
return internalize_div(n);
else if (a.is_idiv(n))
return internalize_idiv(n);
else if (a.is_mod(n))
return internalize_mod(n);
else if (a.is_rem(n))
return internalize_rem(n);
else if (a.is_to_real(n))
return internalize_to_real(n);
else if (a.is_to_int(n))
return internalize_to_int(n);
else if (a.is_sub(n))
return internalize_sub(n);
if (a.is_power(n)) {
// unsupported
found_unsupported_op(n);
return mk_binary_op(n);
}
if (a.is_irrational_algebraic_numeral(n)) {
// unsupported
found_unsupported_op(n);
enode* e = mk_enode(n);
return mk_var(e);
}
if (a.get_family_id() == n->get_family_id()) {
if (!a.is_div0(n) && !a.is_mod0(n) && !a.is_idiv0(n) && !a.is_rem0(n))
found_unsupported_op(n);
if (ctx().e_internalized(n))
return expr2var(n);
for (expr* arg : *n)
ctx().internalize(arg, false);
return mk_var(mk_enode(n));
}
#endif
TRACE("arith_internalize_detail", tout << "before:\n" << mk_pp(n, m) << "\n";);
if (!ctx().e_internalized(n))
ctx().internalize(n, false);
TRACE("arith_internalize_detail", tout << "after:\n" << mk_pp(n, m) << "\n";);
enode* e = ctx().get_enode(n);
if (!th.is_attached_to_var(e))
return mk_var(n);
else
return e->get_th_var(get_id());
}
void linearize_term(expr* term, scoped_internalize_state& st) {
st.push(term, rational::one());
linearize(st);
}
void linearize_ineq(expr* lhs, expr* rhs, scoped_internalize_state& st) {
st.push(lhs, rational::one());
st.push(rhs, rational::minus_one());
linearize(st);
}
void linearize(scoped_internalize_state& st) {
expr_ref_vector & terms = st.terms();
svector<theory_var>& vars = st.vars();
@ -371,6 +559,7 @@ class theory_lra::imp {
st.push(to_app(n)->get_arg(i), -coeffs[index]);
}
}
#if 1
else if (a.is_mul(n, n1, n2) && a.is_extended_numeral(n1, r)) {
coeffs[index] *= r;
terms[index] = n2;
@ -381,6 +570,29 @@ class theory_lra::imp {
terms[index] = n1;
st.to_ensure_enode().push_back(n2);
}
#else
else if (a.is_mul(n, n1, n2) && a.is_extended_numeral(n1, r)) {
internalize_args(n2);
VERIFY(internalize_term(to_app(n2)));
theory_var v = mk_var(n2);
coeffs[vars.size()] = r * coeffs[index];
vars.push_back(v);
get_lpvar(v);
verbose_stream() << v << "\n";
st.to_ensure_enode().push_back(n1);
++index;
}
else if (a.is_mul(n, n1, n2) && a.is_extended_numeral(n2, r)) {
VERIFY(internalize_term(to_app(n1)));
theory_var v = mk_var(n1);
coeffs[vars.size()] = r * coeffs[index];
vars.push_back(v);
get_lpvar(v);
verbose_stream() << v << "\n";
st.to_ensure_enode().push_back(n2);
++index;
}
#endif
else if (a.is_mul(n)) {
theory_var v = internalize_mul(to_app(n));
coeffs[vars.size()] = coeffs[index];
@ -663,8 +875,10 @@ class theory_lra::imp {
for (unsigned i = 0; i < vars.size(); ++i) {
theory_var var = vars[i];
rational const& r = m_columns[var];
if (!r.is_zero()) {
m_left_side.push_back(std::make_pair(r, register_theory_var_in_lar_solver(var)));
if (!r.is_zero()) {
auto vi = register_theory_var_in_lar_solver(var);
vi = lp().ensure_column(vi);
m_left_side.push_back({ r, vi });
m_columns[var].reset();
}
}
@ -672,12 +886,7 @@ class theory_lra::imp {
}
bool all_zeros(vector<rational> const& v) const {
for (rational const& r : v) {
if (!r.is_zero()) {
return false;
}
}
return true;
return all_of(v, [](rational const& r) { return r.is_zero(); });
}
void add_eq_constraint(lp::constraint_index index, enode* n1, enode* n2) {
@ -850,8 +1059,9 @@ class theory_lra::imp {
else if (is_zero(st) && a.is_numeral(term)) {
return lp().local_to_external(get_zero(a.is_int(term)));
}
else {
else {
init_left_side(st);
lpvar vi = get_lpvar(v);
if (vi == UINT_MAX) {
if (m_left_side.empty()) {
@ -862,8 +1072,10 @@ class theory_lra::imp {
return v;
}
if (!st.offset().is_zero()) {
m_left_side.push_back(std::make_pair(st.offset(), get_one(a.is_int(term))));
verbose_stream() << "Offset row " << st.offset() << "\n";
m_left_side.push_back({ st.offset(), get_one(a.is_int(term)) });
}
if (m_left_side.empty()) {
vi = lp().add_var(v, a.is_int(term));
add_def_constraint_and_equality(vi, lp::GE, rational(0));
@ -872,7 +1084,7 @@ class theory_lra::imp {
else {
vi = lp().add_term(m_left_side, v);
SASSERT(lp::tv::is_term(vi));
TRACE("arith_verbose",
TRACE("arith_init",
tout << "v" << v << " := " << mk_pp(term, m)
<< " slack: " << vi << " scopes: " << m_scopes.size() << "\n";
lp().print_term(lp().get_term(lp::tv::raw(vi)), tout) << "\n";);
@ -963,19 +1175,19 @@ public:
m_bool_var2bound.erase(bv);
ctx().set_var_theory(bv, get_id());
if (a.is_le(atom, n1, n2) && a.is_extended_numeral(n2, r) && is_app(n1)) {
v = internalize_def(to_app(n1));
v = internalize_term_core(to_app(n1));
k = lp_api::upper_t;
}
else if (a.is_ge(atom, n1, n2) && a.is_extended_numeral(n2, r) && is_app(n1)) {
v = internalize_def(to_app(n1));
v = internalize_term_core(to_app(n1));
k = lp_api::lower_t;
}
else if (a.is_le(atom, n1, n2) && a.is_extended_numeral(n1, r) && is_app(n2)) {
v = internalize_def(to_app(n2));
v = internalize_term_core(to_app(n2));
k = lp_api::lower_t;
}
else if (a.is_ge(atom, n1, n2) && a.is_extended_numeral(n1, r) && is_app(n2)) {
v = internalize_def(to_app(n2));
v = internalize_term_core(to_app(n2));
k = lp_api::upper_t;
}
else if (a.is_is_int(atom)) {
@ -1007,7 +1219,8 @@ public:
// skip
}
else {
internalize_def(term);
internalize_term2(term);
// internalize_def(term);
}
return true;
}
@ -1098,6 +1311,8 @@ public:
if (num_scopes == 0) {
return;
}
m_has_popped = true;
unsigned old_size = m_scopes.size() - num_scopes;
del_bounds(m_scopes[old_size].m_bounds_lim);
m_asserted_atoms.shrink(m_scopes[old_size].m_asserted_atoms_lim);
@ -1499,6 +1714,8 @@ public:
void random_update() {
if (m_nla && m_nla->need_check())
return;
if (!m_liberal_final_check)
return;
m_tmp_var_set.clear();
m_tmp_var_set.resize(th.get_num_vars());
m_model_eqs.reset();
@ -1536,7 +1753,9 @@ public:
tout << "v" << v << " ";
tout << "\n"; );
if (!vars.empty()) {
verbose_stream() << "random update " << vars.size() << "\n";
lp().random_update(vars.size(), vars.data());
m_changed_assignment = true;
}
}
@ -1552,8 +1771,9 @@ public:
unsigned old_sz = m_assume_eq_candidates.size();
unsigned num_candidates = 0;
int start = ctx().get_random_value();
for (theory_var i = 0; i < sz; ++i) {
for (int i = 0; i < sz; ++i) {
theory_var v = (i + start) % sz;
enode* n1 = get_enode(v);
if (!th.is_relevant_and_shared(n1)) {
continue;
@ -1646,10 +1866,84 @@ public:
return FC_GIVEUP;
}
bool m_has_propagated_fixed = false;
bool m_has_popped = false;
bool propagate_fixed() {
m_has_propagated_fixed = false;
vector<std::tuple<lp::explanation, lp::column_index, bool, lp::mpq>> bounds;
if (!lp().has_fixed_at_bound(bounds))
return false;
// verbose_stream() << "scope " << ctx().get_scope_level() << "\n";
for (auto const& [exp, j, lower, b] : bounds) {
auto t = lp().column2tv(j);
expr_ref trm(m);
if (t.is_term())
trm = term2expr(lp().get_term(t));
else
trm = var2expr(t.id());
expr* v = a.mk_numeral(b, a.is_int(trm));
expr* bound = lower ? a.mk_ge(trm, v) : a.mk_le(trm, v);
literal lit = mk_literal(bound);
reset_evidence();
for (auto ev : exp)
set_evidence(ev.ci(), m_core, m_eqs);
//verbose_stream() << "assign " << lit << " " << mk_pp(bound, m) << " " << ctx().get_assignment(lit) << "\n";
ctx().mark_as_relevant(bound);
//ctx().display(verbose_stream());
assign(lit, m_core, m_eqs, m_params);
/// verbose_stream() << "propagate " << lit << "\n";
//exit(0);
}
m_has_propagated_fixed = true;
m_has_popped = false;
return true;
}
unsigned m_final_check_idx = 0;
distribution m_dist { 0 };
bool m_liberal_final_check = false;
bool m_changed_assignment = false;
final_check_status final_check_eh() {
TRACE("arith_eq_adapter_info", m_arith_eq_adapter.display_already_processed(tout););
TRACE("arith", display(tout););
if (propagate_core())
return FC_CONTINUE;
if (delayed_assume_eqs())
return FC_CONTINUE;
m_liberal_final_check = true;
m_changed_assignment = false;
ctx().push_trail(value_trail<unsigned>(m_final_check_idx));
final_check_status result = final_check_core();
if (result != FC_DONE)
return result;
if (!m_changed_assignment)
return FC_DONE;
m_liberal_final_check = false;
m_changed_assignment = false;
result = final_check_core();
TRACE("arith", tout << "result: " << result << "\n";);
return result;
}
final_check_status final_check_core() {
if (false)
{
verbose_stream() << "final\n";
::statistics stats;
collect_statistics(stats);
stats.display(verbose_stream());
}
#if 0
if (!m_has_propagated_fixed && propagate_fixed())
return FC_CONTINUE;
#endif
if (propagate_core())
return FC_CONTINUE;
m_model_is_initialized = false;
@ -1661,13 +1955,11 @@ public:
}
bool giveup = false;
final_check_status st = FC_DONE;
m_final_check_idx = 0; // remove to experiment.
unsigned old_idx = m_final_check_idx;
switch (is_sat) {
case l_true:
TRACE("arith", display(tout));
// if (lp().has_fixed_at_bound()) // explain and propagate.
#if 0
m_dist.reset();
@ -1691,6 +1983,7 @@ public:
st = check_lia();
break;
default:
verbose_stream() << idx << "\n";
UNREACHABLE();
break;
}
@ -1713,11 +2006,11 @@ public:
switch (m_final_check_idx) {
case 0:
if (assume_eqs())
st = FC_CONTINUE;
st = check_lia();
break;
case 1:
st = check_lia();
if (assume_eqs())
st = FC_CONTINUE;
break;
case 2:
st = check_nla();
@ -2171,7 +2464,7 @@ public:
}
bool can_propagate_core() {
return m_asserted_atoms.size() > m_asserted_qhead || m_new_def;
return m_asserted_atoms.size() > m_asserted_qhead || m_new_def || (m_has_propagated_fixed && m_has_popped);
}
bool propagate() {
@ -2181,8 +2474,9 @@ public:
bool propagate_core() {
m_model_is_initialized = false;
flush_bound_axioms();
if (!can_propagate_core())
if (!can_propagate_core())
return false;
m_new_def = false;
while (m_asserted_qhead < m_asserted_atoms.size() && !ctx().inconsistent() && m.inc()) {
auto [bv, is_true] = m_asserted_atoms[m_asserted_qhead];
@ -2196,6 +2490,10 @@ public:
assert_bound(bv, is_true, *b);
++m_asserted_qhead;
}
if (false && m_has_propagated_fixed && m_has_popped && propagate_fixed())
return true;
if (ctx().inconsistent()) {
m_bv_to_propagate.reset();
return true;
@ -2603,6 +2901,7 @@ public:
mk_clause(~l1, l2, 3, coeffs);
}
}
++m_stats.m_bound_axioms;
}
typedef lp_bounds::iterator iterator;
@ -3305,6 +3604,13 @@ public:
tout << "\n";
display_evidence(tout, m_explanation);
display(tout << "is-conflict: " << is_conflict << "\n"););
TRACE("arith_conflict",
display_evidence(tout, m_explanation);
for (auto lit : m_core)
ctx().display_literal_verbose(tout, lit);
);
for (auto ev : m_explanation)
set_evidence(ev.ci(), m_core, m_eqs);

View file

@ -507,7 +507,7 @@ namespace smt {
TRACE("utvpi", a.display(*this, tout); tout << "\n";);
int edge_id = a.get_asserted_edge();
if (!enable_edge(edge_id)) {
m_graph.traverse_neg_cycle2(m_params.m_arith_stronger_lemmas, m_nc_functor);
m_graph.traverse_neg_cycle2(m_params.m_arith_relax_bounds, m_nc_functor);
set_conflict();
return false;
}