mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
Merge branch 'upstream-master' into develop
Conflicts: src/smt/params/smt_params.cpp src/smt/params/smt_params.h src/smt/smt_context.cpp src/smt/smt_context.h
This commit is contained in:
commit
0862949e66
28 changed files with 691 additions and 170 deletions
|
@ -63,7 +63,6 @@ namespace smt {
|
|||
m_is_diseq_tmp(0),
|
||||
m_units_to_reassert(m_manager),
|
||||
m_qhead(0),
|
||||
m_th_case_split_qhead(0),
|
||||
m_simp_qhead(0),
|
||||
m_simp_counter(0),
|
||||
m_bvar_inc(1.0),
|
||||
|
@ -341,7 +340,6 @@ namespace smt {
|
|||
|
||||
bool context::bcp() {
|
||||
SASSERT(!inconsistent());
|
||||
m_th_case_split_qhead = m_qhead;
|
||||
while (m_qhead < m_assigned_literals.size()) {
|
||||
if (get_cancel_flag()) {
|
||||
return true;
|
||||
|
@ -1777,7 +1775,7 @@ namespace smt {
|
|||
unsigned qhead = m_qhead;
|
||||
if (!bcp())
|
||||
return false;
|
||||
if (!propagate_th_case_split())
|
||||
if (!propagate_th_case_split(qhead))
|
||||
return false;
|
||||
if (get_cancel_flag()) {
|
||||
m_qhead = qhead;
|
||||
|
@ -2977,7 +2975,6 @@ namespace smt {
|
|||
public:
|
||||
case_split_insert_trail(literal l):
|
||||
l(l) {
|
||||
|
||||
}
|
||||
virtual void undo(context & ctx) {
|
||||
ctx.undo_th_case_split(l);
|
||||
|
@ -2988,23 +2985,19 @@ namespace smt {
|
|||
TRACE("theory_case_split", display_literals_verbose(tout << "theory case split: ", num_lits, lits); tout << std::endl;);
|
||||
// If we don't use the theory case split heuristic,
|
||||
// for each pair of literals (l1, l2) we add the clause (~l1 OR ~l2)
|
||||
// to enforce the condition that more than one literal can't be
|
||||
// assigned 'true' simultaneously.
|
||||
// to enforce the condition that at most one literal can be assigned 'true'.
|
||||
if (!m_fparams.m_theory_case_split) {
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
for (unsigned j = i+1; j < num_lits; ++j) {
|
||||
literal l1 = lits[i];
|
||||
literal l2 = lits[j];
|
||||
literal excl[2] = {~l1, ~l2};
|
||||
justification * j_excl = 0;
|
||||
mk_clause(2, excl, j_excl);
|
||||
mk_clause(~l1, ~l2, (justification*) 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
literal_vector new_case_split; // TODO is it okay to allocate this on the stack?
|
||||
literal_vector new_case_split;
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
literal l = lits[i];
|
||||
// TODO do we need to enforce this invariant? can we make undo information work without it?
|
||||
SASSERT(!m_all_th_case_split_literals.contains(l.index()));
|
||||
m_all_th_case_split_literals.insert(l.index());
|
||||
push_trail(case_split_insert_trail(l));
|
||||
|
@ -3020,11 +3013,11 @@ namespace smt {
|
|||
m_literal2casesplitsets[l.index()].push_back(new_case_split);
|
||||
}
|
||||
TRACE("theory_case_split", tout << "tracking case split literal set { ";
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
tout << lits[i].index() << " ";
|
||||
}
|
||||
tout << "}" << std::endl;
|
||||
);
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
tout << lits[i].index() << " ";
|
||||
}
|
||||
tout << "}" << std::endl;
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3041,7 +3034,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
bool context::propagate_th_case_split() {
|
||||
bool context::propagate_th_case_split(unsigned qhead) {
|
||||
if (m_all_th_case_split_literals.empty())
|
||||
return true;
|
||||
|
||||
|
@ -3049,46 +3042,33 @@ namespace smt {
|
|||
// not counting any literals that get assigned by this method
|
||||
// this relies on bcp() to give us its old m_qhead and therefore
|
||||
// bcp() should always be called before this method
|
||||
unsigned assigned_literal_idx = m_th_case_split_qhead;
|
||||
unsigned assigned_literal_end = m_assigned_literals.size();
|
||||
while(assigned_literal_idx < assigned_literal_end) {
|
||||
literal l = m_assigned_literals[assigned_literal_idx];
|
||||
for (; qhead < assigned_literal_end; ++qhead) {
|
||||
literal l = m_assigned_literals[qhead];
|
||||
TRACE("theory_case_split", tout << "check literal " << l.index() << std::endl; display_literal_verbose(tout, l); tout << std::endl;);
|
||||
++assigned_literal_idx;
|
||||
// check if this literal participates in any theory case split
|
||||
if (m_all_th_case_split_literals.contains(l.index())) {
|
||||
TRACE("theory_case_split", tout << "assigned literal " << l.index() << " is a theory case split literal" << std::endl;);
|
||||
// now find the sets of literals which contain l
|
||||
vector<literal_vector> case_split_sets = m_literal2casesplitsets.get(l.index(), vector<literal_vector>());
|
||||
for (vector<literal_vector>::const_iterator it = case_split_sets.begin(); it != case_split_sets.end(); ++it) {
|
||||
literal_vector case_split_set = *it;
|
||||
TRACE("theory_case_split", tout << "found case split set { ";
|
||||
for(literal_vector::iterator set_it = case_split_set.begin(); set_it != case_split_set.end(); ++set_it) {
|
||||
tout << set_it->index() << " ";
|
||||
}
|
||||
tout << "}" << std::endl;);
|
||||
for(literal_vector::iterator set_it = case_split_set.begin(); set_it != case_split_set.end(); ++set_it) {
|
||||
literal l2 = *set_it;
|
||||
if (l2 != l) {
|
||||
b_justification js(l);
|
||||
switch (get_assignment(l2)) {
|
||||
case l_false:
|
||||
TRACE("theory_case_split", tout << "case split literal " << l2.index() << " is already assigned False" << std::endl;);
|
||||
break;
|
||||
// TODO these next two cases can be combined. I'm doing this for debugging purposes
|
||||
case l_undef:
|
||||
TRACE("theory_case_split", tout << "case split literal " << l2.index() << " is not assigned" << std::endl;);
|
||||
assign(~l2, js);
|
||||
break;
|
||||
case l_true:
|
||||
TRACE("theory_case_split", tout << "case split literal " << l2.index() << " is already assigned True" << std::endl;);
|
||||
assign(~l2, js);
|
||||
break;
|
||||
}
|
||||
if (inconsistent()) {
|
||||
TRACE("theory_case_split", tout << "conflict detected!" << std::endl;);
|
||||
return false;
|
||||
}
|
||||
if (!m_all_th_case_split_literals.contains(l.index())) {
|
||||
continue;
|
||||
}
|
||||
TRACE("theory_case_split", tout << "assigned literal " << l.index() << " is a theory case split literal" << std::endl;);
|
||||
// now find the sets of literals which contain l
|
||||
vector<literal_vector> const& case_split_sets = m_literal2casesplitsets[l.index()];
|
||||
for (vector<literal_vector>::const_iterator it = case_split_sets.begin(); it != case_split_sets.end(); ++it) {
|
||||
literal_vector case_split_set = *it;
|
||||
TRACE("theory_case_split", tout << "found case split set { ";
|
||||
for(literal_vector::iterator set_it = case_split_set.begin(); set_it != case_split_set.end(); ++set_it) {
|
||||
tout << set_it->index() << " ";
|
||||
}
|
||||
tout << "}" << std::endl;);
|
||||
for(literal_vector::iterator set_it = case_split_set.begin(); set_it != case_split_set.end(); ++set_it) {
|
||||
literal l2 = *set_it;
|
||||
if (l2 != l) {
|
||||
b_justification js(l);
|
||||
TRACE("theory_case_split", tout << "case split literal "; l2.display(tout, m_manager, m_bool_var2expr.c_ptr()););
|
||||
assign(~l2, js);
|
||||
if (inconsistent()) {
|
||||
TRACE("theory_case_split", tout << "conflict detected!" << std::endl;);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,7 +234,6 @@ namespace smt {
|
|||
uint_set m_all_th_case_split_literals;
|
||||
vector<literal_vector> m_th_case_split_sets;
|
||||
u_map< vector<literal_vector> > m_literal2casesplitsets; // returns the case split literal sets that a literal participates in
|
||||
unsigned m_th_case_split_qhead;
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
|
@ -851,7 +850,7 @@ namespace smt {
|
|||
// helper function for trail
|
||||
void undo_th_case_split(literal l);
|
||||
|
||||
bool propagate_th_case_split();
|
||||
bool propagate_th_case_split(unsigned qhead);
|
||||
|
||||
bool_var mk_bool_var(expr * n);
|
||||
|
||||
|
|
|
@ -405,7 +405,6 @@ namespace smt {
|
|||
bool context::validate_justification(bool_var v, bool_var_data const& d, b_justification const& j) {
|
||||
if (j.get_kind() == b_justification::CLAUSE && v != true_bool_var) {
|
||||
clause* cls = j.get_clause();
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
literal l = cls->get_literal(0);
|
||||
if (l.var() != v) {
|
||||
l = cls->get_literal(1);
|
||||
|
|
|
@ -552,6 +552,7 @@ namespace smt {
|
|||
bool is_int(theory_var v) const { return m_data[v].m_is_int; }
|
||||
bool is_int_src(theory_var v) const { return m_util.is_int(var2expr(v)); }
|
||||
bool is_real(theory_var v) const { return !is_int(v); }
|
||||
bool is_real_src(theory_var v) const { return !is_int_src(v); }
|
||||
bool get_implied_old_value(theory_var v, inf_numeral & r) const;
|
||||
inf_numeral const & get_implied_value(theory_var v) const;
|
||||
inf_numeral const & get_quasi_base_value(theory_var v) const { return get_implied_value(v); }
|
||||
|
|
|
@ -465,7 +465,7 @@ namespace smt {
|
|||
TRACE("arith_axiom", tout << mk_pp(ante, m) << "\n" << mk_pp(conseq, m) << "\n";
|
||||
tout << s_ante << "\n" << s_conseq << "\n";);
|
||||
|
||||
literal lits[2] = {l_ante, l_conseq};
|
||||
// literal lits[2] = {l_ante, l_conseq};
|
||||
mk_clause(l_ante, l_conseq, 0, 0);
|
||||
if (ctx.relevancy()) {
|
||||
if (l_ante == false_literal) {
|
||||
|
|
|
@ -444,7 +444,7 @@ namespace smt {
|
|||
m_asserted_bounds.push_back(new_bound);
|
||||
// copy justification to new bound
|
||||
dependency2new_bound(dep, *new_bound);
|
||||
TRACE("buggy_bound", new_bound->display(*this, tout); tout << "\n";);
|
||||
TRACE("non_linear", new_bound->display(*this, tout); tout << "\n";);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -457,8 +457,19 @@ namespace smt {
|
|||
bool r = false;
|
||||
if (!i.minus_infinity()) {
|
||||
inf_numeral new_lower(i.get_lower_value());
|
||||
if (i.is_lower_open())
|
||||
new_lower += get_epsilon(v);
|
||||
if (i.is_lower_open()) {
|
||||
if (is_int(v)) {
|
||||
if (new_lower.is_int()) {
|
||||
new_lower += rational::one();
|
||||
}
|
||||
else {
|
||||
new_lower = ceil(new_lower.get_rational());
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_lower += get_epsilon(v);
|
||||
}
|
||||
}
|
||||
bound * old_lower = lower(v);
|
||||
if (old_lower == 0 || new_lower > old_lower->get_value()) {
|
||||
TRACE("non_linear", tout << "NEW lower bound for v" << v << " " << new_lower << "\n";
|
||||
|
@ -469,8 +480,19 @@ namespace smt {
|
|||
}
|
||||
if (!i.plus_infinity()) {
|
||||
inf_numeral new_upper(i.get_upper_value());
|
||||
if (i.is_upper_open())
|
||||
new_upper -= get_epsilon(v);
|
||||
if (i.is_upper_open()) {
|
||||
if (is_int(v)) {
|
||||
if (new_upper.is_int()) {
|
||||
new_upper -= rational::one();
|
||||
}
|
||||
else {
|
||||
new_upper = floor(new_upper.get_rational());
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_upper -= get_epsilon(v);
|
||||
}
|
||||
}
|
||||
bound * old_upper = upper(v);
|
||||
if (old_upper == 0 || new_upper < old_upper->get_value()) {
|
||||
TRACE("non_linear", tout << "NEW upper bound for v" << v << " " << new_upper << "\n";
|
||||
|
@ -819,6 +841,7 @@ namespace smt {
|
|||
if (is_fixed(_var))
|
||||
r *= lower_bound(_var).get_rational();
|
||||
}
|
||||
TRACE("arith", tout << mk_pp(m, get_manager()) << " " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -896,7 +919,7 @@ namespace smt {
|
|||
|
||||
// Assert the equality
|
||||
// (= (* x_1 ... x_n) k)
|
||||
TRACE("non_linear", tout << "all variables are fixed.\n";);
|
||||
TRACE("non_linear", tout << "all variables are fixed, and bound is: " << k << "\n";);
|
||||
new_lower = alloc(derived_bound, v, inf_numeral(k), B_LOWER);
|
||||
new_upper = alloc(derived_bound, v, inf_numeral(k), B_UPPER);
|
||||
}
|
||||
|
@ -953,7 +976,8 @@ namespace smt {
|
|||
new_upper->m_eqs.append(new_lower->m_eqs);
|
||||
|
||||
TRACE("non_linear",
|
||||
tout << "lower: " << new_lower << " upper: " << new_upper << "\n";
|
||||
new_lower->display(*this, tout << "lower: "); tout << "\n";
|
||||
new_upper->display(*this, tout << "upper: "); tout << "\n";
|
||||
for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_upper->m_lits[j]);
|
||||
tout << " ";
|
||||
|
|
|
@ -762,6 +762,21 @@ namespace smt {
|
|||
TRACE("bv", tout << mk_pp(cond, get_manager()) << "\n"; tout << l << "\n";); \
|
||||
}
|
||||
|
||||
void theory_bv::internalize_sub(app *n) {
|
||||
SASSERT(!get_context().e_internalized(n));
|
||||
SASSERT(n->get_num_args() == 2);
|
||||
process_args(n);
|
||||
ast_manager & m = get_manager();
|
||||
enode * e = mk_enode(n);
|
||||
expr_ref_vector arg1_bits(m), arg2_bits(m), bits(m);
|
||||
get_arg_bits(e, 0, arg1_bits);
|
||||
get_arg_bits(e, 1, arg2_bits);
|
||||
SASSERT(arg1_bits.size() == arg2_bits.size());
|
||||
expr_ref carry(m);
|
||||
m_bb.mk_subtracter(arg1_bits.size(), arg1_bits.c_ptr(), arg2_bits.c_ptr(), bits, carry);
|
||||
init_bits(e, bits);
|
||||
}
|
||||
|
||||
MK_UNARY(internalize_not, mk_not);
|
||||
MK_UNARY(internalize_redand, mk_redand);
|
||||
MK_UNARY(internalize_redor, mk_redor);
|
||||
|
@ -848,6 +863,7 @@ namespace smt {
|
|||
switch (term->get_decl_kind()) {
|
||||
case OP_BV_NUM: internalize_num(term); return true;
|
||||
case OP_BADD: internalize_add(term); return true;
|
||||
case OP_BSUB: internalize_sub(term); return true;
|
||||
case OP_BMUL: internalize_mul(term); return true;
|
||||
case OP_BSDIV_I: internalize_sdiv(term); return true;
|
||||
case OP_BUDIV_I: internalize_udiv(term); return true;
|
||||
|
|
|
@ -172,6 +172,7 @@ namespace smt {
|
|||
bool get_fixed_value(theory_var v, numeral & result) const;
|
||||
void internalize_num(app * n);
|
||||
void internalize_add(app * n);
|
||||
void internalize_sub(app * n);
|
||||
void internalize_mul(app * n);
|
||||
void internalize_udiv(app * n);
|
||||
void internalize_sdiv(app * n);
|
||||
|
|
|
@ -3874,8 +3874,8 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
|
|||
}
|
||||
else if (n1 != n2 && m_util.is_re(n1->get_owner())) {
|
||||
warning_msg("equality between regular expressions is not yet supported");
|
||||
eautomaton* a1 = get_automaton(n1->get_owner());
|
||||
eautomaton* a2 = get_automaton(n2->get_owner());
|
||||
// eautomaton* a1 = get_automaton(n1->get_owner());
|
||||
// eautomaton* a2 = get_automaton(n2->get_owner());
|
||||
// eautomaton* b1 = mk_difference(*a1, *a2);
|
||||
// eautomaton* b2 = mk_difference(*a2, *a1);
|
||||
// eautomaton* c = mk_union(*b1, *b2);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue