3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-07 16:31:55 +00:00

initial integration of opt

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-04-27 19:13:00 -07:00
commit 8205b45839
114 changed files with 3680 additions and 1370 deletions

View file

@ -3942,7 +3942,7 @@ namespace smt {
#endif
virtual void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector<enode> & used_enodes) {
TRACE("trigger_bug", tout << "found match\n";);
TRACE("trigger_bug", tout << "found match " << mk_pp(qa, m_ast_manager) << "\n";);
#ifdef Z3DEBUG
if (m_check_missing_instances) {
if (!m_context.slow_contains_instance(qa, num_bindings, bindings)) {

View file

@ -81,7 +81,7 @@ ext_numeral & ext_numeral::operator*=(ext_numeral const & other) {
m_value.reset();
return *this;
}
if (is_infinite() || other.is_infinite()) {
if (sign() == other.sign())
m_kind = PLUS_INFINITY;
@ -203,7 +203,7 @@ interval::interval(v_dependency_manager & m, rational const & val, v_dependency
m_lower_dep(l_dep),
m_upper_dep(u_dep) {
}
/**
\brief Create intervals (-oo, val], (-oo, val), [val, oo), (val, oo)
*/
@ -271,8 +271,8 @@ interval & interval::operator-=(interval const & other) {
return operator+=(tmp);
}
v_dependency * interval::join(v_dependency * d1, v_dependency * d2, v_dependency * d3, v_dependency * d4) {
return m_manager.mk_join(m_manager.mk_join(d1, d2), m_manager.mk_join(d3,d4));
v_dependency * interval::join(v_dependency * d1, v_dependency * d2, v_dependency * d3, v_dependency * d4) {
return m_manager.mk_join(m_manager.mk_join(d1, d2), m_manager.mk_join(d3,d4));
}
/**
@ -318,7 +318,7 @@ interval & interval::operator*=(interval const & other) {
v_dependency * d_d = other.m_upper_dep;
TRACE("interval_bug", tout << "operator*= " << *this << " " << other << "\n";);
if (is_N()) {
if (other.is_N()) {
// x <= b <= 0, y <= d <= 0 --> b*d <= x*y
@ -452,7 +452,7 @@ interval & interval::operator*=(interval const & other) {
m_upper_dep = m_upper.is_infinite() ? 0 : join(b_d, d_d, a_d);
}
else {
// 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
// 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
// x <= b, y <= d --> x*y <= b*d (uses the fact that x is pos (a is not negative) or y is pos (c is not negative))
TRACE("interval_bug", tout << "(P, P)\n";);
SASSERT(other.is_P());
@ -467,7 +467,7 @@ interval & interval::operator*=(interval const & other) {
}
}
TRACE("interval_bug", tout << "operator*= result: " << *this << "\n";);
CTRACE("interval", !(!(contains_zero1 || contains_zero2) || contains_zero()),
CTRACE("interval", !(!(contains_zero1 || contains_zero2) || contains_zero()),
tout << "contains_zero1: " << contains_zero1 << ", contains_zero2: " << contains_zero2 << ", contains_zero(): " << contains_zero() << "\n";);
SASSERT(!(contains_zero1 || contains_zero2) || contains_zero());
return *this;
@ -482,7 +482,7 @@ bool interval::contains_zero() const {
tout << "m_upper.is_zero: " << m_upper.is_zero() << "\n";
tout << "m_upper_open: " << m_upper_open << "\n";
tout << "result: " << ((m_lower.is_neg() || (m_lower.is_zero() && !m_lower_open)) && (m_upper.is_pos() || (m_upper.is_zero() && !m_upper_open))) << "\n";);
return
return
(m_lower.is_neg() || (m_lower.is_zero() && !m_lower_open)) &&
(m_upper.is_pos() || (m_upper.is_zero() && !m_upper_open));
}
@ -510,7 +510,7 @@ interval & interval::inv() {
ext_numeral new_upper;
if (m_lower.is_zero()) {
SASSERT(m_lower_open);
ext_numeral plus_infinity(true);
ext_numeral plus_infinity(true);
new_upper = plus_infinity;
}
else {
@ -595,7 +595,7 @@ void interval::expt(unsigned n) {
else if (m_upper.is_neg()) {
// [l, u]^n = [u^n, l^n] if u < 0
// a <= x <= b < 0 --> x^n <= a^n (use lower and upper bound -- need the fact that x is negative)
// x <= b < 0 --> b^n <= x^n
// x <= b < 0 --> b^n <= x^n
std::swap(m_lower, m_upper);
std::swap(m_lower_open, m_upper_open);
std::swap(m_lower_dep, m_upper_dep);
@ -614,7 +614,7 @@ void interval::expt(unsigned n) {
m_upper = m_lower;
m_upper_open = m_lower_open;
}
m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep);
m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep);
m_lower = ext_numeral(0);
m_lower_open = false;
m_lower_dep = 0;

View file

@ -64,5 +64,6 @@ def_module_params(module_name='smt',
('core.validate', BOOL, False, 'validate unsat core produced by SMT context'),
('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'),
('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'),
('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core')
('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'),
('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body')
))

View file

@ -59,9 +59,9 @@ namespace smt {
SASSERT(n->trans_reaches(n->get_root()));
while (n) {
if (Set)
n->set_mark();
n->set_mark2();
else
n->unset_mark();
n->unset_mark2();
n = n->m_trans.m_target;
}
}
@ -84,7 +84,7 @@ namespace smt {
mark_enodes_in_trans<true>(n1);
while (true) {
SASSERT(n2);
if (n2->is_marked()) {
if (n2->is_marked2()) {
mark_enodes_in_trans<false>(n1);
return n2;
}

View file

@ -30,6 +30,7 @@ namespace smt {
index_set::iterator it = vars.begin(), end = vars.end();
for (; it != end; ++it) {
expr* e = bool_var2expr(*it);
e = m_assumption2orig.find(e);
premises.push_back(get_assignment(*it) != l_false ? e : m_manager.mk_not(e));
}
return mk_and(premises);
@ -44,13 +45,14 @@ namespace smt {
// - e is an equality between a variable and value that is to be fixed.
// - e is a data-type recognizer of a variable that is to be fixed.
//
void context::extract_fixed_consequences(literal lit, obj_map<expr, expr*>& vars, index_set const& assumptions, expr_ref_vector& conseq) {
void context::extract_fixed_consequences(literal lit, index_set const& assumptions, expr_ref_vector& conseq) {
ast_manager& m = m_manager;
datatype_util dt(m);
expr* e1, *e2;
expr_ref fml(m);
if (lit == true_literal) return;
expr* e = bool_var2expr(lit.var());
TRACE("context", display(tout << mk_pp(e, m) << "\n"););
index_set s;
if (assumptions.contains(lit.var())) {
s.insert(lit.var());
@ -65,26 +67,32 @@ namespace smt {
}
tout << "\n";);
bool found = false;
if (vars.contains(e)) {
if (m_var2val.contains(e)) {
found = true;
m_var2val.erase(e);
e = m_var2orig.find(e);
fml = lit.sign() ? m.mk_not(e) : e;
vars.erase(e);
}
else if (!lit.sign() && m.is_eq(e, e1, e2)) {
if (vars.contains(e2)) {
std::swap(e1, e2);
}
if (vars.contains(e1) && m.is_value(e2)) {
if (m_var2val.contains(e2) && m.is_value(e1)) {
found = true;
fml = e;
vars.erase(e1);
m_var2val.erase(e2);
e2 = m_var2orig.find(e2);
std::swap(e1, e2);
fml = m.mk_eq(e1, e2);
}
else if (m_var2val.contains(e1) && m.is_value(e2)) {
found = true;
m_var2val.erase(e1);
e1 = m_var2orig.find(e1);
fml = m.mk_eq(e1, e2);
}
}
else if (!lit.sign() && is_app(e) && dt.is_recognizer(to_app(e)->get_decl())) {
if (vars.contains(to_app(e)->get_arg(0))) {
if (m_var2val.contains(to_app(e)->get_arg(0))) {
found = true;
fml = m.mk_eq(to_app(e)->get_arg(0), m.mk_const(dt.get_recognizer_constructor(to_app(e)->get_decl())));
vars.erase(to_app(e)->get_arg(0));
m_var2val.erase(to_app(e)->get_arg(0));
}
}
if (found) {
@ -94,6 +102,7 @@ namespace smt {
}
void context::justify(literal lit, index_set& s) {
ast_manager& m = m_manager;
b_justification js = get_justification(lit.var());
switch (js.get_kind()) {
case b_justification::CLAUSE: {
@ -119,6 +128,9 @@ namespace smt {
literal_vector literals;
m_conflict_resolution->justification2literals(js.get_justification(), literals);
for (unsigned j = 0; j < literals.size(); ++j) {
if (!m_antecedents.contains(literals[j].var())) {
TRACE("context", tout << literals[j] << " " << mk_pp(bool_var2expr(literals[j].var()), m) << "\n";);
}
s |= m_antecedents.find(literals[j].var());
}
break;
@ -126,13 +138,13 @@ namespace smt {
}
}
void context::extract_fixed_consequences(unsigned& start, obj_map<expr, expr*>& vars, index_set const& assumptions, expr_ref_vector& conseq) {
void context::extract_fixed_consequences(unsigned& start, index_set const& assumptions, expr_ref_vector& conseq) {
pop_to_search_lvl();
SASSERT(!inconsistent());
literal_vector const& lits = assigned_literals();
unsigned sz = lits.size();
for (unsigned i = start; i < sz; ++i) {
extract_fixed_consequences(lits[i], vars, assumptions, conseq);
extract_fixed_consequences(lits[i], assumptions, conseq);
}
start = sz;
SASSERT(!inconsistent());
@ -150,10 +162,10 @@ namespace smt {
// rules out as many non-fixed variables as possible.
//
unsigned context::delete_unfixed(obj_map<expr, expr*>& var2val, expr_ref_vector& unfixed) {
unsigned context::delete_unfixed(expr_ref_vector& unfixed) {
ast_manager& m = m_manager;
ptr_vector<expr> to_delete;
obj_map<expr,expr*>::iterator it = var2val.begin(), end = var2val.end();
obj_map<expr,expr*>::iterator it = m_var2val.begin(), end = m_var2val.end();
for (; it != end; ++it) {
expr* k = it->m_key;
expr* v = it->m_value;
@ -189,7 +201,7 @@ namespace smt {
}
}
for (unsigned i = 0; i < to_delete.size(); ++i) {
var2val.remove(to_delete[i]);
m_var2val.remove(to_delete[i]);
unfixed.push_back(to_delete[i]);
}
return to_delete.size();
@ -202,12 +214,12 @@ namespace smt {
// Add a clause to short-circuit the congruence justifications for
// next rounds.
//
unsigned context::extract_fixed_eqs(obj_map<expr, expr*>& var2val, expr_ref_vector& conseq) {
unsigned context::extract_fixed_eqs(expr_ref_vector& conseq) {
TRACE("context", tout << "extract fixed consequences\n";);
ast_manager& m = m_manager;
ptr_vector<expr> to_delete;
expr_ref fml(m), eq(m);
obj_map<expr,expr*>::iterator it = var2val.begin(), end = var2val.end();
obj_map<expr,expr*>::iterator it = m_var2val.begin(), end = m_var2val.end();
for (; it != end; ++it) {
expr* k = it->m_key;
expr* v = it->m_value;
@ -220,7 +232,7 @@ namespace smt {
s |= m_antecedents.find(literals[i].var());
}
fml = m.mk_eq(k, v);
fml = m.mk_eq(m_var2orig.find(k), v);
fml = m.mk_implies(antecedent2fml(s), fml);
conseq.push_back(fml);
to_delete.push_back(k);
@ -235,16 +247,20 @@ namespace smt {
}
}
for (unsigned i = 0; i < to_delete.size(); ++i) {
var2val.remove(to_delete[i]);
m_var2val.remove(to_delete[i]);
}
return to_delete.size();
}
literal context::mk_diseq(expr* e, expr* val) {
ast_manager& m = m_manager;
if (m.is_bool(e)) {
if (m.is_bool(e) && b_internalized(e)) {
return literal(get_bool_var(e), m.is_true(val));
}
else if (m.is_bool(e)) {
internalize_formula(e, false);
return literal(get_bool_var(e), !m.is_true(val));
}
else {
expr_ref eq(mk_eq_atom(e, val), m);
internalize_formula(eq, false);
@ -252,43 +268,85 @@ namespace smt {
}
}
lbool context::get_consequences(expr_ref_vector const& assumptions,
expr_ref_vector const& vars,
lbool context::get_consequences(expr_ref_vector const& assumptions0,
expr_ref_vector const& vars0,
expr_ref_vector& conseq,
expr_ref_vector& unfixed) {
m_antecedents.reset();
m_antecedents.insert(true_literal.var(), index_set());
pop_to_base_lvl();
ast_manager& m = m_manager;
expr_ref_vector vars(m), assumptions(m);
m_var2val.reset();
m_var2orig.reset();
m_assumption2orig.reset();
bool pushed = false;
for (unsigned i = 0; i < vars0.size(); ++i) {
expr* v = vars0[i];
if (is_uninterp_const(v)) {
vars.push_back(v);
m_var2orig.insert(v, v);
}
else {
if (!pushed) {
pushed = true;
push();
}
expr_ref c(m.mk_fresh_const("v", m.get_sort(v)), m);
expr_ref eq(m.mk_eq(c, v), m);
assert_expr(eq);
vars.push_back(c);
m_var2orig.insert(c, v);
}
}
for (unsigned i = 0; i < assumptions0.size(); ++i) {
expr* a = assumptions0[i];
if (is_uninterp_const(a)) {
assumptions.push_back(a);
m_assumption2orig.insert(a, a);
}
else {
if (!pushed) {
pushed = true;
push();
}
expr_ref c(m.mk_fresh_const("a", m.get_sort(a)), m);
expr_ref eq(m.mk_eq(c, a), m);
assert_expr(eq);
assumptions.push_back(c);
m_assumption2orig.insert(c, a);
}
}
lbool is_sat = check(assumptions.size(), assumptions.c_ptr());
if (is_sat != l_true) {
TRACE("context", tout << is_sat << "\n";);
if (pushed) pop(1);
return is_sat;
}
obj_map<expr, expr*> var2val;
index_set _assumptions;
for (unsigned i = 0; i < assumptions.size(); ++i) {
_assumptions.insert(get_literal(assumptions[i]).var());
_assumptions.insert(get_literal(assumptions[i].get()).var());
}
model_ref mdl;
get_model(mdl);
ast_manager& m = m_manager;
expr_ref_vector trail(m);
model_evaluator eval(*mdl.get());
expr_ref val(m);
TRACE("context", model_pp(tout, *mdl););
for (unsigned i = 0; i < vars.size(); ++i) {
eval(vars[i], val);
eval(vars[i].get(), val);
if (m.is_value(val)) {
trail.push_back(val);
var2val.insert(vars[i], val);
m_var2val.insert(vars[i].get(), val);
}
else {
unfixed.push_back(vars[i]);
unfixed.push_back(vars[i].get());
}
}
unsigned num_units = 0;
extract_fixed_consequences(num_units, var2val, _assumptions, conseq);
extract_fixed_consequences(num_units, _assumptions, conseq);
app_ref eq(m);
TRACE("context",
tout << "vars: " << vars.size() << "\n";
@ -298,11 +356,12 @@ namespace smt {
unsigned num_fixed_eqs = 0;
unsigned chunk_size = 100;
while (!var2val.empty()) {
obj_map<expr,expr*>::iterator it = var2val.begin(), end = var2val.end();
while (!m_var2val.empty()) {
obj_map<expr,expr*>::iterator it = m_var2val.begin(), end = m_var2val.end();
unsigned num_vars = 0;
for (; it != end && num_vars < chunk_size; ++it) {
if (get_cancel_flag()) {
if (pushed) pop(1);
return l_undef;
}
expr* e = it->m_key;
@ -332,6 +391,7 @@ namespace smt {
while (true) {
is_sat = bounded_search();
if (is_sat != l_true && m_last_search_failure != OK) {
if (pushed) pop(1);
return is_sat;
}
if (is_sat == l_undef) {
@ -347,18 +407,21 @@ namespace smt {
m_not_l = null_literal;
}
if (is_sat == l_true) {
delete_unfixed(var2val, unfixed);
delete_unfixed(unfixed);
}
extract_fixed_consequences(num_units, var2val, _assumptions, conseq);
num_fixed_eqs += extract_fixed_eqs(var2val, conseq);
IF_VERBOSE(1, display_consequence_progress(verbose_stream(), num_iterations, var2val.size(), conseq.size(),
extract_fixed_consequences(num_units, _assumptions, conseq);
num_fixed_eqs += extract_fixed_eqs(conseq);
IF_VERBOSE(1, display_consequence_progress(verbose_stream(), num_iterations, m_var2val.size(), conseq.size(),
unfixed.size(), num_fixed_eqs););
TRACE("context", display_consequence_progress(tout, num_iterations, var2val.size(), conseq.size(),
TRACE("context", display_consequence_progress(tout, num_iterations, m_var2val.size(), conseq.size(),
unfixed.size(), num_fixed_eqs););
}
end_search();
DEBUG_CODE(validate_consequences(assumptions, vars, conseq, unfixed););
if (pushed) {
pop(1);
}
return l_true;
}

View file

@ -304,7 +304,6 @@ namespace smt {
TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " ";
display_literal_verbose(tout, l); tout << " level: " << m_scope_lvl << "\n";
display(tout, j););
SASSERT(l.var() < static_cast<int>(m_b_internalized_stack.size()));
m_assigned_literals.push_back(l);
m_assignment[l.index()] = l_true;
m_assignment[(~l).index()] = l_false;
@ -319,14 +318,23 @@ namespace smt {
d.m_phase_available = true;
d.m_phase = !l.sign();
TRACE("phase_selection", tout << "saving phase, is_pos: " << d.m_phase << " l: " << l << "\n";);
TRACE("relevancy",
tout << "is_atom: " << d.is_atom() << " is relevant: " << is_relevant_core(bool_var2expr(l.var())) << "\n";);
if (d.is_atom() && (m_fparams.m_relevancy_lvl == 0 || (m_fparams.m_relevancy_lvl == 1 && !d.is_quantifier()) || is_relevant_core(bool_var2expr(l.var()))))
tout << "is_atom: " << d.is_atom() << " is relevant: " << is_relevant_core(l) << "\n";);
if (d.is_atom() && (m_fparams.m_relevancy_lvl == 0 || (m_fparams.m_relevancy_lvl == 1 && !d.is_quantifier()) || is_relevant_core(l)))
m_atom_propagation_queue.push_back(l);
if (m_manager.has_trace_stream())
trace_assign(l, j, decision);
m_case_split_queue->assign_lit_eh(l);
// a unit is asserted at search level. Mark it as relevant.
// this addresses bug... where a literal becomes fixed to true (false)
// as a conflict gets assigned misses relevancy (and quantifier instantiation).
//
if (false && !decision && relevancy() && at_search_level() && !is_relevant_core(l)) {
mark_as_relevant(l);
}
}
bool context::bcp() {
@ -1634,7 +1642,7 @@ namespace smt {
m_atom_propagation_queue.push_back(literal(v, val == l_false));
}
}
TRACE("propagate_relevancy", tout << "marking as relevant:\n" << mk_bounded_pp(n, m_manager) << "\n";);
TRACE("propagate_relevancy", tout << "marking as relevant:\n" << mk_bounded_pp(n, m_manager) << " " << m_scope_lvl << "\n";);
#ifndef SMTCOMP
m_case_split_queue->relevant_eh(n);
#endif
@ -3073,11 +3081,11 @@ namespace smt {
m_assumptions.reset();
}
void context::mk_unsat_core() {
lbool context::mk_unsat_core() {
SASSERT(inconsistent());
if (!tracking_assumptions()) {
SASSERT(m_assumptions.empty());
return;
return l_false;
}
uint_set already_found_assumptions;
literal_vector::const_iterator it = m_conflict_resolution->begin_unsat_core();
@ -3102,7 +3110,17 @@ namespace smt {
for (unsigned i = 0; i < sz; i++) {
tout << mk_pp(m_unsat_core.get(i), m_manager) << "\n";
});
validate_unsat_core();
validate_unsat_core();
// theory validation of unsat core
ptr_vector<theory>::iterator th_it = m_theory_set.begin();
ptr_vector<theory>::iterator th_end = m_theory_set.end();
for (; th_it != th_end; ++th_it) {
lbool theory_result = (*th_it)->validate_unsat_core(m_unsat_core);
if (theory_result == l_undef) {
return l_undef;
}
}
return l_false;
}
/**
@ -3145,6 +3163,14 @@ namespace smt {
SASSERT(m_scope_lvl == 0);
SASSERT(!m_setup.already_configured());
setup_context(m_fparams.m_auto_config);
expr_ref_vector theory_assumptions(m_manager);
add_theory_assumptions(theory_assumptions);
if (!theory_assumptions.empty()) {
TRACE("search", tout << "Adding theory assumptions to context" << std::endl;);
return check(theory_assumptions.size(), theory_assumptions.c_ptr(), reset_cancel, true);
}
internalize_assertions();
lbool r = l_undef;
if (m_asserted_formulas.inconsistent()) {
@ -3206,7 +3232,15 @@ namespace smt {
(*it)->setup();
}
lbool context::check(unsigned num_assumptions, expr * const * assumptions, bool reset_cancel) {
void context::add_theory_assumptions(expr_ref_vector & theory_assumptions) {
ptr_vector<theory>::iterator it = m_theory_set.begin();
ptr_vector<theory>::iterator end = m_theory_set.end();
for (; it != end; ++it) {
(*it)->add_theory_assumptions(theory_assumptions);
}
}
lbool context::check(unsigned ext_num_assumptions, expr * const * ext_assumptions, bool reset_cancel, bool already_did_theory_assumptions) {
m_stats.m_num_checks++;
TRACE("check_bug", tout << "STARTING check(num_assumptions, assumptions)\n";
tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n";
@ -3217,6 +3251,15 @@ namespace smt {
m_unsat_core.reset();
if (!check_preamble(reset_cancel))
return l_undef;
expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions);
if (!already_did_theory_assumptions) {
add_theory_assumptions(all_assumptions);
}
unsigned num_assumptions = all_assumptions.size();
expr * const * assumptions = all_assumptions.c_ptr();
if (!validate_assumptions(num_assumptions, assumptions))
return l_undef;
TRACE("check_bug", tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n";);
@ -3240,13 +3283,21 @@ namespace smt {
TRACE("after_internalization", display(tout););
if (inconsistent()) {
VERIFY(!resolve_conflict()); // build the proof
mk_unsat_core();
r = l_false;
lbool result = mk_unsat_core();
if (result == l_undef) {
r = l_undef;
} else {
r = l_false;
}
}
else {
r = search();
if (r == l_false)
mk_unsat_core();
if (r == l_false) {
lbool result = mk_unsat_core();
if (result == l_undef) {
r = l_undef;
}
}
}
}
}
@ -3750,6 +3801,7 @@ namespace smt {
// I invoke pop_scope_core instead of pop_scope because I don't want
// to reset cached generations... I need them to rebuild the literals
// of the new conflict clause.
if (relevancy()) record_relevancy(num_lits, lits);
unsigned num_bool_vars = pop_scope_core(m_scope_lvl - new_lvl);
SASSERT(m_scope_lvl == new_lvl);
// the logical context may still be in conflict after
@ -3781,6 +3833,7 @@ namespace smt {
}
}
}
if (relevancy()) restore_relevancy(num_lits, lits);
// Resetting the cache manually because I did not invoke pop_scope, but pop_scope_core
reset_cache_generation();
TRACE("resolve_conflict_bug",
@ -3863,6 +3916,28 @@ namespace smt {
}
return false;
}
/*
\brief we record and restore relevancy information for literals in conflict clauses.
A literal may have been marked relevant within the scope that gets popped during
conflict resolution. In this case, the literal is no longer marked as relevant after
the pop. This can cause quantifier instantiation to miss relevant triggers and thereby
cause incmpleteness.
*/
void context::record_relevancy(unsigned n, literal const* lits) {
m_relevant_conflict_literals.reset();
for (unsigned i = 0; i < n; ++i) {
m_relevant_conflict_literals.push_back(is_relevant(lits[i]));
}
}
void context::restore_relevancy(unsigned n, literal const* lits) {
for (unsigned i = 0; i < n; ++i) {
if (m_relevant_conflict_literals[i] && !is_relevant(lits[i])) {
mark_as_relevant(lits[i]);
}
}
}
void context::get_relevant_labels(expr* cnstr, buffer<symbol> & result) {
if (m_fparams.m_check_at_labels) {
@ -4195,42 +4270,21 @@ namespace smt {
for (unsigned i = 0; i < m_asserted_formulas.get_num_formulas(); ++i) {
expr* e = m_asserted_formulas.get_formula(i);
if (is_quantifier(e)) {
TRACE("context", tout << mk_pp(e, m) << "\n";);
quantifier* q = to_quantifier(e);
if (!m.is_rec_fun_def(q)) continue;
SASSERT(q->get_num_patterns() == 1);
SASSERT(q->get_num_patterns() == 2);
expr* fn = to_app(q->get_pattern(0))->get_arg(0);
expr* body = to_app(q->get_pattern(1))->get_arg(0);
SASSERT(is_app(fn));
func_decl* f = to_app(fn)->get_decl();
expr* eq = q->get_expr();
expr_ref body(m);
if (is_fun_def(fn, q->get_expr(), body)) {
func_interp* fi = alloc(func_interp, m, f->get_arity());
fi->set_else(body);
m_model->register_decl(f, fi);
}
func_interp* fi = alloc(func_interp, m, f->get_arity());
fi->set_else(body);
m_model->register_decl(f, fi);
}
}
}
bool context::is_fun_def(expr* f, expr* body, expr_ref& result) {
expr* t1, *t2, *t3;
if (m_manager.is_eq(body, t1, t2) || m_manager.is_iff(body, t1, t2)) {
if (t1 == f) return result = t2, true;
if (t2 == f) return result = t1, true;
return false;
}
if (m_manager.is_ite(body, t1, t2, t3)) {
expr_ref body1(m_manager), body2(m_manager);
if (is_fun_def(f, t2, body1) && is_fun_def(f, t3, body2)) {
// f is not free in t1
result = m_manager.mk_ite(t1, body1, body2);
return true;
}
}
return false;
}
};

View file

@ -1066,7 +1066,9 @@ namespace smt {
void reset_assumptions();
void mk_unsat_core();
void add_theory_assumptions(expr_ref_vector & theory_assumptions);
lbool mk_unsat_core();
void validate_unsat_core();
@ -1110,6 +1112,10 @@ namespace smt {
bool is_relevant_core(expr * n) const { return m_relevancy_propagator->is_relevant(n); }
svector<bool> m_relevant_conflict_literals;
void record_relevancy(unsigned n, literal const* lits);
void restore_relevancy(unsigned n, literal const* lits);
public:
// event handler for relevancy_propagator class
void relevant_eh(expr * n);
@ -1131,6 +1137,10 @@ namespace smt {
return is_relevant(l.var());
}
bool is_relevant_core(literal l) const {
return is_relevant_core(bool_var2expr(l.var()));
}
void mark_as_relevant(expr * n) { m_relevancy_propagator->mark_as_relevant(n); m_relevancy_propagator->propagate(); }
void mark_as_relevant(enode * n) { mark_as_relevant(n->get_owner()); }
@ -1166,8 +1176,6 @@ namespace smt {
void add_rec_funs_to_model();
bool is_fun_def(expr* f, expr* q, expr_ref& body);
public:
bool can_propagate() const;
@ -1378,14 +1386,17 @@ namespace smt {
typedef hashtable<unsigned, u_hash, u_eq> index_set;
//typedef uint_set index_set;
u_map<index_set> m_antecedents;
void extract_fixed_consequences(literal lit, obj_map<expr, expr*>& var2val, index_set const& assumptions, expr_ref_vector& conseq);
void extract_fixed_consequences(unsigned& idx, obj_map<expr, expr*>& var2val, index_set const& assumptions, expr_ref_vector& conseq);
obj_map<expr, expr*> m_var2orig;
obj_map<expr, expr*> m_assumption2orig;
obj_map<expr, expr*> m_var2val;
void extract_fixed_consequences(literal lit, index_set const& assumptions, expr_ref_vector& conseq);
void extract_fixed_consequences(unsigned& idx, index_set const& assumptions, expr_ref_vector& conseq);
void display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq);
unsigned delete_unfixed(obj_map<expr, expr*>& var2val, expr_ref_vector& unfixed);
unsigned delete_unfixed(expr_ref_vector& unfixed);
unsigned extract_fixed_eqs(obj_map<expr, expr*>& var2val, expr_ref_vector& conseq);
unsigned extract_fixed_eqs(expr_ref_vector& conseq);
expr_ref antecedent2fml(index_set const& ante);
@ -1442,7 +1453,7 @@ namespace smt {
void pop(unsigned num_scopes);
lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true);
lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true, bool already_did_theory_assumptions = false);
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed);

View file

@ -433,6 +433,9 @@ namespace smt {
if (!is_ground(n)) {
continue;
}
if (is_quantifier(n) && m.is_rec_fun_def(to_quantifier(n))) {
continue;
}
switch (get_assignment(*it)) {
case l_undef:
break;

View file

@ -246,13 +246,15 @@ namespace smt {
simple_justification::simple_justification(region & r, unsigned num_lits, literal const * lits):
m_num_literals(num_lits) {
m_literals = new (r) literal[num_lits];
memcpy(m_literals, lits, sizeof(literal) * num_lits);
if (num_lits != 0) {
m_literals = new (r) literal[num_lits];
memcpy(m_literals, lits, sizeof(literal) * num_lits);
#ifdef Z3DEBUG
for (unsigned i = 0; i < num_lits; i++) {
SASSERT(lits[i] != null_literal);
}
for (unsigned i = 0; i < num_lits; i++) {
SASSERT(lits[i] != null_literal);
}
#endif
}
}
void simple_justification::get_antecedents(conflict_resolution & cr) {

View file

@ -316,9 +316,9 @@ namespace smt {
return false;
}
bool model_checker::check_rec_fun(quantifier* q) {
bool model_checker::check_rec_fun(quantifier* q, bool strict_rec_fun) {
TRACE("model_checker", tout << mk_pp(q, m) << "\n";);
SASSERT(q->get_num_patterns() == 1);
SASSERT(q->get_num_patterns() == 2); // first pattern is the function, second is the body.
expr* fn = to_app(q->get_pattern(0))->get_arg(0);
SASSERT(is_app(fn));
func_decl* f = to_app(fn)->get_decl();
@ -340,7 +340,7 @@ namespace smt {
}
sub(q->get_expr(), num_decls, args.c_ptr(), tmp);
m_curr_model->eval(tmp, result, true);
if (m.is_false(result)) {
if (strict_rec_fun ? !m.is_true(result) : m.is_false(result)) {
add_instance(q, args, 0);
return false;
}
@ -365,10 +365,10 @@ namespace smt {
bool model_checker::check(proto_model * md, obj_map<enode, app *> const & root2value) {
SASSERT(md != 0);
m_root2value = &root2value;
ptr_vector<quantifier>::const_iterator it = m_qm->begin_quantifiers();
ptr_vector<quantifier>::const_iterator end = m_qm->end_quantifiers();
if (it == end)
if (m_qm->num_quantifiers() == 0)
return true;
if (m_iteration_idx >= m_params.m_mbqi_max_iterations) {
@ -393,6 +393,36 @@ namespace smt {
bool found_relevant = false;
unsigned num_failures = 0;
check_quantifiers(false, found_relevant, num_failures);
if (found_relevant)
m_iteration_idx++;
TRACE("model_checker", tout << "model after check:\n"; model_pp(tout, *md););
TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";);
m_max_cexs += m_params.m_mbqi_max_cexs;
if (num_failures == 0 && !m_context->validate_model()) {
num_failures = 1;
// this time force expanding recursive function definitions
// that are not forced true in the current model.
check_quantifiers(true, found_relevant, num_failures);
}
if (num_failures == 0)
m_curr_model->cleanup();
if (m_params.m_mbqi_trace) {
if (num_failures == 0)
verbose_stream() << "(smt.mbqi :succeeded true)\n";
else
verbose_stream() << "(smt.mbqi :num-failures " << num_failures << ")\n";
}
return num_failures == 0;
}
void model_checker::check_quantifiers(bool strict_rec_fun, bool& found_relevant, unsigned& num_failures) {
ptr_vector<quantifier>::const_iterator it = m_qm->begin_quantifiers();
ptr_vector<quantifier>::const_iterator end = m_qm->end_quantifiers();
for (; it != end; ++it) {
quantifier * q = *it;
if(!m_qm->mbqi_enabled(q)) continue;
@ -406,7 +436,7 @@ namespace smt {
}
found_relevant = true;
if (m.is_rec_fun_def(q)) {
if (!check_rec_fun(q)) {
if (!check_rec_fun(q, strict_rec_fun)) {
TRACE("model_checker", tout << "checking recursive function failed\n";);
num_failures++;
}
@ -420,26 +450,6 @@ namespace smt {
}
}
}
if (found_relevant)
m_iteration_idx++;
TRACE("model_checker", tout << "model after check:\n"; model_pp(tout, *md););
TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";);
m_max_cexs += m_params.m_mbqi_max_cexs;
if (num_failures == 0 && !m_context->validate_model()) {
num_failures = 1;
}
if (num_failures == 0)
m_curr_model->cleanup();
if (m_params.m_mbqi_trace) {
if (num_failures == 0)
verbose_stream() << "(smt.mbqi :succeeded true)\n";
else
verbose_stream() << "(smt.mbqi :num-failures " << num_failures << ")\n";
}
return num_failures == 0;
}
void model_checker::init_search_eh() {

View file

@ -59,7 +59,8 @@ namespace smt {
void assert_neg_q_m(quantifier * q, expr_ref_vector & sks);
bool add_blocking_clause(model * cex, expr_ref_vector & sks);
bool check(quantifier * q);
bool check_rec_fun(quantifier* q);
bool check_rec_fun(quantifier* q, bool strict_rec_fun);
void check_quantifiers(bool strict_rec_fun, bool& found_relevant, unsigned& num_failures);
struct instance {
quantifier * m_q;

View file

@ -52,8 +52,9 @@ namespace smt {
m_qi_queue.setup();
}
bool has_trace_stream() const { return m_context.get_manager().has_trace_stream(); }
std::ostream & trace_stream() { return m_context.get_manager().trace_stream(); }
ast_manager& m() const { return m_context.get_manager(); }
bool has_trace_stream() const { return m().has_trace_stream(); }
std::ostream & trace_stream() { return m().trace_stream(); }
quantifier_stat * get_stat(quantifier * q) const {
return m_quantifier_stat.find(q);
@ -110,8 +111,9 @@ namespace smt {
unsigned max_top_generation,
ptr_vector<enode> & used_enodes) {
max_generation = std::max(max_generation, get_generation(q));
if (m_num_instances > m_params.m_qi_max_instances)
if (m_num_instances > m_params.m_qi_max_instances) {
return false;
}
get_stat(q)->update_max_generation(max_generation);
fingerprint * f = m_context.add_fingerprint(q, q->get_id(), num_bindings, bindings);
if (f) {
@ -132,9 +134,17 @@ namespace smt {
}
m_qi_queue.insert(f, pat, max_generation, min_top_generation, max_top_generation); // TODO
m_num_instances++;
return true;
}
return false;
TRACE("quantifier",
tout << mk_pp(q, m()) << " ";
for (unsigned i = 0; i < num_bindings; ++i) {
tout << mk_pp(bindings[i]->get_owner(), m()) << " ";
}
tout << "\n";
tout << "inserted: " << (f != 0) << "\n";
);
return f != 0;
}
void init_search_eh() {
@ -186,7 +196,7 @@ namespace smt {
}
bool check_quantifier(quantifier* q) {
return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // && !m_context.get_manager().is_rec_fun_def(q);
return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // && !m().is_rec_fun_def(q);
}
bool quick_check_quantifiers() {
@ -387,6 +397,10 @@ namespace smt {
return m_imp->m_quantifiers.end();
}
unsigned quantifier_manager::num_quantifiers() const {
return m_imp->m_quantifiers.size();
}
// The default plugin uses E-matching, MBQI and quick-checker
class default_qm_plugin : public quantifier_manager_plugin {
quantifier_manager * m_qm;
@ -501,13 +515,13 @@ namespace smt {
SASSERT(m_context->get_manager().is_pattern(mp));
bool unary = (mp->get_num_args() == 1);
if (!unary && j >= num_eager_multi_patterns) {
TRACE("assign_quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n"
TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n"
<< "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns
<< " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";);
m_lazy_mam->add_pattern(q, mp);
}
else {
TRACE("assign_quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";);
TRACE("quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";);
m_mam->add_pattern(q, mp);
}
if (!unary)

View file

@ -91,6 +91,8 @@ namespace smt {
ptr_vector<quantifier>::const_iterator begin_quantifiers() const;
ptr_vector<quantifier>::const_iterator end_quantifiers() const;
unsigned num_quantifiers() const;
};
class quantifier_manager_plugin {

View file

@ -38,6 +38,7 @@ namespace smt {
bool m_minimizing_core;
bool m_core_extend_patterns;
unsigned m_core_extend_patterns_max_distance;
bool m_core_extend_nonlocal_patterns;
obj_map<expr, expr*> m_name2assertion;
public:
@ -48,13 +49,15 @@ namespace smt {
m_context(m, m_smt_params),
m_minimizing_core(false),
m_core_extend_patterns(false),
m_core_extend_patterns_max_distance(UINT_MAX) {
m_core_extend_patterns_max_distance(UINT_MAX),
m_core_extend_nonlocal_patterns(false) {
m_logic = l;
if (m_logic != symbol::null)
m_context.set_logic(m_logic);
smt_params_helper smth(p);
m_core_extend_patterns = smth.core_extend_patterns();
m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance();
m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns();
}
virtual solver * translate(ast_manager & m, params_ref const & p) {
@ -81,6 +84,8 @@ namespace smt {
m_context.updt_params(p);
smt_params_helper smth(p);
m_core_extend_patterns = smth.core_extend_patterns();
m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance();
m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns();
}
virtual void collect_param_descrs(param_descrs & r) {
@ -172,6 +177,8 @@ namespace smt {
if (m_core_extend_patterns)
add_pattern_literals_to_core(r);
if (m_core_extend_nonlocal_patterns)
add_nonlocal_pattern_literals_to_core(r);
}
virtual void get_model(model_ref & m) {
@ -250,7 +257,7 @@ namespace smt {
}
};
void collect_pattern_func_decls(expr_ref & e, func_decl_set & fds) {
void collect_pattern_fds(expr_ref & e, func_decl_set & fds) {
collect_pattern_fds_proc p(get_manager(), fds);
expr_mark visited;
for_each_expr(p, visited, e);
@ -295,7 +302,7 @@ namespace smt {
expr_ref name(core[i], m);
SASSERT(m_name2assertion.contains(name));
expr_ref assrtn(m_name2assertion.find(name), m);
collect_pattern_func_decls(assrtn, pattern_fds);
collect_pattern_fds(assrtn, pattern_fds);
}
if (!pattern_fds.empty()) {
@ -317,6 +324,55 @@ namespace smt {
break;
}
}
struct collect_body_fds_proc {
ast_manager & m;
func_decl_set & m_fds;
collect_body_fds_proc(ast_manager & m, func_decl_set & fds) :
m(m), m_fds(fds) {
}
void operator()(var * n) {}
void operator()(app * n) {}
void operator()(quantifier * n) {
collect_fds_proc p(m, m_fds);
expr_fast_mark1 visited;
quick_for_each_expr(p, visited, n->get_expr());
}
};
void collect_body_func_decls(expr_ref & e, func_decl_set & fds) {
ast_manager & m = get_manager();
collect_body_fds_proc p(m, fds);
expr_mark visited;
for_each_expr(p, visited, e);
}
void add_nonlocal_pattern_literals_to_core(ptr_vector<expr> & core) {
ast_manager & m = get_manager();
obj_map<expr, expr*>::iterator it = m_name2assertion.begin();
obj_map<expr, expr*>::iterator end = m_name2assertion.end();
for (unsigned i = 0; it != end; it++, i++) {
expr_ref name(it->m_key, m);
expr_ref assrtn(it->m_value, m);
if (!core.contains(name)) {
func_decl_set pattern_fds, body_fds;
collect_pattern_fds(assrtn, pattern_fds);
collect_body_func_decls(assrtn, body_fds);
func_decl_set::iterator pit = pattern_fds.begin();
func_decl_set::iterator pend= pattern_fds.end();
for (; pit != pend; pit++) {
func_decl * fd = *pit;
if (!body_fds.contains(fd)) {
core.insert(name);
break;
}
}
}
}
}
};
};

View file

@ -177,6 +177,22 @@ namespace smt {
virtual void restart_eh() {
}
/**
\brief This method is called by smt_context before the search starts
to get any extra assumptions the theory wants to use.
(See theory_str for an example)
*/
virtual void add_theory_assumptions(expr_ref_vector & assumptions) {
}
/**
\brief This method is called from smt_context when an unsat core is generated.
The theory may change the answer to UNKNOWN by returning l_undef from this method.
*/
virtual lbool validate_unsat_core(expr_ref_vector & unsat_core) {
return l_false;
}
/**
\brief This method is invoked before the search starts.
*/

View file

@ -40,7 +40,7 @@ namespace smt {
template<typename Ext>
void theory_arith<Ext>::found_underspecified_op(app * n) {
if (!m_found_underspecified_op) {
TRACE("arith", tout << "found non underspecificed expression:\n" << mk_pp(n, get_manager()) << "\n";);
TRACE("arith", tout << "found underspecificed expression:\n" << mk_pp(n, get_manager()) << "\n";);
get_context().push_trail(value_trail<context, bool>(m_found_underspecified_op));
m_found_underspecified_op = true;
}
@ -395,6 +395,7 @@ namespace smt {
template<typename Ext>
theory_var theory_arith<Ext>::internalize_div(app * n) {
if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n);
found_underspecified_op(n);
theory_var s = mk_binary_op(n);
context & ctx = get_context();
@ -418,7 +419,7 @@ namespace smt {
template<typename Ext>
theory_var theory_arith<Ext>::internalize_mod(app * n) {
TRACE("arith_mod", tout << "internalizing...\n" << mk_pp(n, get_manager()) << "\n";);
found_underspecified_op(n);
if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n);
theory_var s = mk_binary_op(n);
context & ctx = get_context();
if (!ctx.relevancy())
@ -428,7 +429,7 @@ namespace smt {
template<typename Ext>
theory_var theory_arith<Ext>::internalize_rem(app * n) {
found_underspecified_op(n);
if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n);
theory_var s = mk_binary_op(n);
context & ctx = get_context();
if (!ctx.relevancy()) {

View file

@ -206,7 +206,8 @@ namespace smt {
numeral k = ceil(get_value(v));
rational _k = k.to_rational();
expr_ref bound(get_manager());
bound = m_util.mk_ge(get_enode(v)->get_owner(), m_util.mk_numeral(_k, true));
expr* e = get_enode(v)->get_owner();
bound = m_util.mk_ge(e, m_util.mk_numeral(_k, m_util.is_int(e)));
TRACE("arith_int", tout << mk_bounded_pp(bound, get_manager()) << "\n";);
context & ctx = get_context();
ctx.internalize(bound, true);
@ -371,7 +372,7 @@ namespace smt {
ctx.mk_th_axiom(get_id(), l1, l2);
TRACE("theory_arith_int",
TRACE("arith_int",
tout << "cut: (or " << mk_pp(p1, get_manager()) << " " << mk_pp(p2, get_manager()) << ")\n";
);
@ -1407,6 +1408,7 @@ namespace smt {
if (m_params.m_arith_int_eq_branching && branch_infeasible_int_equality()) {
return FC_CONTINUE;
}
theory_var int_var = find_infeasible_int_base_var();
if (int_var != null_theory_var) {
TRACE("arith_int", tout << "v" << int_var << " does not have an integer assignment: " << get_value(int_var) << "\n";);

View file

@ -339,8 +339,13 @@ namespace smt {
tout << mk_pp(var, get_manager()) << "\n";
tout << "power " << power << ": " << expt(i, power) << "\n";
display_interval(tout << "target before: ", target); tout << "\n";);
i.expt(power);
target *= i;
get_manager().limit().inc((target.is_lower_open() || target.minus_infinity()) ? 1 : target.get_lower_value().bitsize());
get_manager().limit().inc((target.is_upper_open() || target.plus_infinity()) ? 1 : target.get_upper_value().bitsize());
TRACE("non_linear", display_interval(tout << "target after: ", target); tout << "\n";);
}

View file

@ -607,12 +607,13 @@ namespace smt {
}
expr_ref sum(m);
arith_simp().mk_add(sz, args.c_ptr(), sum);
literal l(mk_eq(n, sum, false));
TRACE("bv",
tout << mk_pp(n, m) << "\n";
tout << mk_pp(sum, m) << "\n";
ctx.display_literal_verbose(tout, l);
tout << "\n";
);
literal l(mk_eq(n, sum, false));
ctx.mark_as_relevant(l);
ctx.mk_th_axiom(get_id(), 1, &l);

View file

@ -868,7 +868,8 @@ namespace smt {
e = ctx.get_enode(to_app(n));
}
else {
e = ctx.mk_enode(to_app(n), false, false, true);
ctx.internalize(n, false);
e = ctx.get_enode(n);
}
v = e->get_th_var(get_id());
if (v == null_theory_var) {
@ -901,7 +902,7 @@ namespace smt {
objective_term const& objective = m_objectives[v];
has_shared = false;
IF_VERBOSE(1,
IF_VERBOSE(4,
for (unsigned i = 0; i < objective.size(); ++i) {
verbose_stream() << objective[i].second
<< " * v" << objective[i].first << " ";
@ -991,9 +992,12 @@ namespace smt {
if (num_nodes <= v && v < num_nodes + num_edges) {
unsigned edge_id = v - num_nodes;
literal lit = m_edges[edge_id].m_justification;
get_context().literal2expr(lit, tmp);
core.push_back(tmp);
if (lit != null_literal) {
get_context().literal2expr(lit, tmp);
core.push_back(tmp);
}
}
TRACE("opt", tout << core << "\n";);
}
for (unsigned i = 0; i < num_nodes; ++i) {
mpq_inf const& val = S.get_value(i);
@ -1005,7 +1009,8 @@ namespace smt {
inf_eps result(rational(0), r);
blocker = mk_gt(v, result);
IF_VERBOSE(10, verbose_stream() << blocker << "\n";);
return result;
r += m_objective_consts[v];
return inf_eps(rational(0), r);
}
default:
TRACE("opt", tout << "unbounded\n"; );
@ -1016,6 +1021,7 @@ namespace smt {
template<typename Ext>
theory_var theory_dense_diff_logic<Ext>::add_objective(app* term) {
TRACE("opt", tout << mk_pp(term, get_manager()) << "\n";);
objective_term objective;
theory_var result = m_objectives.size();
rational q(1), r(0);
@ -1050,6 +1056,7 @@ namespace smt {
ast_manager& m = get_manager();
objective_term const& t = m_objectives[v];
expr_ref e(m), f(m), f2(m);
TRACE("opt", tout << "mk_ineq " << v << " " << val << "\n";);
if (t.size() == 1 && t[0].second.is_one()) {
f = get_enode(t[0].first)->get_owner();
}

View file

@ -255,6 +255,11 @@ final_check_status theory_seq::final_check_eh() {
TRACE("seq", tout << ">>solve_eqs\n";);
return FC_CONTINUE;
}
if (check_contains()) {
++m_stats.m_propagate_contains;
TRACE("seq", tout << ">>propagate_contains\n";);
return FC_CONTINUE;
}
if (solve_nqs(0)) {
++m_stats.m_solve_nqs;
TRACE("seq", tout << ">>solve_nqs\n";);
@ -290,11 +295,6 @@ final_check_status theory_seq::final_check_eh() {
TRACE("seq", tout << ">>propagate_automata\n";);
return FC_CONTINUE;
}
if (check_contains()) {
++m_stats.m_propagate_contains;
TRACE("seq", tout << ">>propagate_contains\n";);
return FC_CONTINUE;
}
if (is_solved()) {
TRACE("seq", tout << ">>is_solved\n";);
return FC_DONE;
@ -1159,7 +1159,7 @@ bool theory_seq::check_extensionality() {
}
/*
\brief check negated contains constriants.
\brief check negated contains constraints.
*/
bool theory_seq::check_contains() {
context & ctx = get_context();
@ -1199,6 +1199,11 @@ bool theory_seq::is_solved() {
IF_VERBOSE(10, display_disequation(verbose_stream() << "(seq.giveup ", m_nqs[0]); verbose_stream() << " is unsolved)\n";);
return false;
}
if (!m_ncs.empty()) {
TRACE("seq", display_nc(tout << "(seq.giveup ", m_ncs[0]); tout << " is unsolved)\n";);
IF_VERBOSE(10, display_nc(verbose_stream() << "(seq.giveup ", m_ncs[0]); verbose_stream() << " is unsolved)\n";);
return false;
}
return true;
}
@ -1981,6 +1986,23 @@ bool theory_seq::solve_nc(unsigned idx) {
}
if (c != n.contains()) {
m_ncs.push_back(nc(c, deps));
m_new_propagation = true;
return true;
}
expr* e1, *e2;
if (m.is_eq(c, e1, e2)) {
literal eq = mk_eq(e1, e2, false);
propagate_lit(deps, 0, 0, ~eq);
return true;
}
if (m.is_or(c)) {
for (unsigned i = 0; i < to_app(c)->get_num_args(); ++i) {
expr_ref ci(to_app(c)->get_arg(i), m);
m_ncs.push_back(nc(ci, deps));
}
m_new_propagation = true;
return true;
}
return false;
@ -2344,6 +2366,17 @@ bool theory_seq::add_itos_axiom(expr* e) {
return false;
}
add_axiom(mk_eq(e2, n, false));
#if 1
expr_ref num_re(m), opt_re(m);
num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9")));
num_re = m_util.re.mk_plus(num_re);
opt_re = m_util.re.mk_opt(m_util.re.mk_to_re(m_util.str.mk_string(symbol("-"))));
num_re = m_util.re.mk_concat(opt_re, num_re);
app_ref in_re(m_util.re.mk_in_re(e, num_re), m);
internalize_term(in_re);
propagate_in_re(in_re, true);
#endif
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
return true;
}
@ -2403,6 +2436,18 @@ void theory_seq::display(std::ostream & out) const {
}
}
if (!m_ncs.empty()) {
out << "Non contains:\n";
for (unsigned i = 0; i < m_ncs.size(); ++i) {
display_nc(out, m_ncs[i]);
}
}
}
void theory_seq::display_nc(std::ostream& out, nc const& nc) const {
out << "not " << mk_pp(nc.contains(), m) << "\n";
display_deps(out << " <- ", nc.deps()); out << "\n";
}
void theory_seq::display_equations(std::ostream& out) const {
@ -2719,7 +2764,9 @@ bool theory_seq::can_propagate() {
expr_ref theory_seq::canonize(expr* e, dependency*& eqs) {
expr_ref result = expand(e, eqs);
TRACE("seq", tout << mk_pp(e, m) << " expands to " << result << "\n";);
m_rewrite(result);
TRACE("seq", tout << mk_pp(e, m) << " rewrites to " << result << "\n";);
return result;
}
@ -3494,6 +3541,7 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) {
let e = at(s, i)
0 <= i < len(s) -> s = xey & len(x) = i & len(e) = 1
i < 0 \/ i >= len(s) -> e = empty
*/
void theory_seq::add_at_axiom(expr* e) {
@ -3507,13 +3555,18 @@ void theory_seq::add_at_axiom(expr* e) {
expr_ref y = mk_skolem(m_post, s, mk_sub(mk_sub(len_s, i), one));
expr_ref xey = mk_concat(x, e, y);
expr_ref len_x(m_util.str.mk_length(x), m);
expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
literal i_ge_0 = mk_literal(m_autil.mk_ge(i, zero));
literal i_ge_len_s = mk_literal(m_autil.mk_ge(mk_sub(i, m_util.str.mk_length(s)), zero));
add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(s, xey));
add_axiom(~i_ge_0, i_ge_len_s, mk_eq(one, len_e, false));
add_axiom(~i_ge_0, i_ge_len_s, mk_eq(i, len_x, false));
add_axiom(i_ge_0, mk_eq(s, emp, false));
add_axiom(~i_ge_len_s, mk_eq(s, emp, false));
}
/**
@ -4469,10 +4522,11 @@ bool theory_seq::canonizes(bool sign, expr* e) {
context& ctx = get_context();
dependency* deps = 0;
expr_ref cont = canonize(e, deps);
TRACE("seq", tout << mk_pp(e, m) << " -> " << cont << "\n";);
TRACE("seq", tout << mk_pp(e, m) << " -> " << cont << "\n";
if (deps) display_deps(tout, deps););
if ((m.is_true(cont) && !sign) ||
(m.is_false(cont) && sign)) {
TRACE("seq", display(tout););
TRACE("seq", display(tout); tout << ctx.get_assignment(ctx.get_literal(e)) << "\n";);
propagate_lit(deps, 0, 0, ctx.get_literal(e));
return true;
}

View file

@ -570,6 +570,7 @@ namespace smt {
void display_disequation(std::ostream& out, ne const& e) const;
void display_deps(std::ostream& out, dependency* deps) const;
void display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const;
void display_nc(std::ostream& out, nc const& nc) const;
public:
theory_seq(ast_manager& m);
virtual ~theory_seq();