3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-07 03:31:23 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2019-08-23 23:29:10 +03:00
parent de69b01e92
commit a337a51374
28 changed files with 486 additions and 144 deletions

View file

@ -326,6 +326,7 @@ namespace smt {
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.
@ -2005,6 +2006,7 @@ namespace smt {
SASSERT(m_flushing || !cls->in_reinit_stack());
if (log)
m_clause_proof.del(*cls);
CTRACE("context", !m_flushing, display_clause_smt2(tout << "deleting ", *cls) << "\n";);
if (!cls->deleted())
remove_cls_occs(cls);
cls->deallocate(m_manager);
@ -2549,13 +2551,14 @@ namespace smt {
for(; it != end; ++it) {
clause * cls = *it;
SASSERT(!cls->in_reinit_stack());
TRACE("simplify_clauses_bug", display_clause(tout, cls); tout << "\n";);
if (cls->deleted()) {
TRACE("simplify_clauses_bug", display_clause(tout << "deleted\n", cls) << "\n";);
del_clause(true, cls);
num_del_clauses++;
}
else if (simplify_clause(*cls)) {
TRACE("simplify_clauses_bug", display_clause_smt2(tout << "simplified\n", *cls) << "\n";);
for (unsigned idx = 0; idx < 2; idx++) {
literal l0 = (*cls)[idx];
b_justification l0_js = get_justification(l0.var());
@ -3335,6 +3338,33 @@ namespace smt {
if (r == l_true && get_cancel_flag()) {
r = l_undef;
}
if (r == l_true && gparams::get_value("model_validate") == "true") {
for (theory* t : m_theory_set) {
t->validate_model(*m_model);
}
for (literal lit : m_assigned_literals) {
if (!is_relevant(lit)) continue;
expr* v = m_bool_var2expr[lit.var()];
if (lit.sign() ? m_model->is_true(v) : m_model->is_false(v)) {
IF_VERBOSE(10, verbose_stream()
<< "invalid assignment " << (lit.sign() ? "true" : "false")
<< " to #" << v->get_id() << " := " << mk_bounded_pp(v, m_manager, 1) << "\n");
}
}
for (clause* cls : m_aux_clauses) {
bool found = false;
for (literal lit : *cls) {
expr* v = m_bool_var2expr[lit.var()];
if (lit.sign() ? !m_model->is_true(v) : !m_model->is_false(v)) {
found = true;
break;
}
}
if (!found) {
IF_VERBOSE(10, display_clause_smt2(verbose_stream() << "not satisfied:\n", *cls) << "\n");
}
}
}
return r;
}

View file

@ -1314,6 +1314,10 @@ namespace smt {
return display_literals(out, lits.size(), lits.c_ptr());
}
std::ostream& display_literal_smt2(std::ostream& out, literal lit) const;
std::ostream& display_literals_smt2(std::ostream& out, unsigned num_lits, literal const* lits) const;
std::ostream& display_literal_verbose(std::ostream & out, literal lit) const;
std::ostream& display_literals_verbose(std::ostream & out, unsigned num_lits, literal const * lits) const;
@ -1326,13 +1330,15 @@ namespace smt {
void display_watch_lists(std::ostream & out) const;
void display_clause_detail(std::ostream & out, clause const * cls) const;
std::ostream& display_clause_detail(std::ostream & out, clause const * cls) const;
void display_clause(std::ostream & out, clause const * cls) const;
std::ostream& display_clause(std::ostream & out, clause const * cls) const;
void display_clauses(std::ostream & out, ptr_vector<clause> const & v) const;
std::ostream& display_clause_smt2(std::ostream & out, clause const& cls) const;
void display_binary_clauses(std::ostream & out) const;
std::ostream& display_clauses(std::ostream & out, ptr_vector<clause> const & v) const;
std::ostream& display_binary_clauses(std::ostream & out) const;
void display_assignment(std::ostream & out) const;

View file

@ -101,12 +101,24 @@ namespace smt {
display_verbose(out, m_manager, num_lits, lits, m_bool_var2expr.c_ptr(), "\n"); return out;
}
void context::display_literal_info(std::ostream & out, literal l) const {
l.display_compact(out, m_bool_var2expr.c_ptr());
std::ostream& context::display_literal_smt2(std::ostream& out, literal l) const {
if (l.sign())
out << " (not " << mk_bounded_pp(bool_var2expr(l.var()), m_manager, 10) << ") ";
else
out << " " << mk_bounded_pp(bool_var2expr(l.var()), m_manager, 10) << " ";
return out;
}
std::ostream& context::display_literals_smt2(std::ostream& out, unsigned num_lits, literal const* lits) const {
for (unsigned i = 0; i < num_lits; ++i) {
display_literal_smt2(out, lits[i]) << "\n";
}
return out;
}
void context::display_literal_info(std::ostream & out, literal l) const {
l.display_compact(out, m_bool_var2expr.c_ptr());
display_literal_smt2(out, l);
out << "relevant: " << is_relevant(bool_var2expr(l.var())) << ", val: " << get_assignment(l) << "\n";
}
@ -144,7 +156,7 @@ namespace smt {
}
}
void context::display_clause_detail(std::ostream & out, clause const * cls) const {
std::ostream& context::display_clause_detail(std::ostream & out, clause const * cls) const {
out << "lemma: " << cls->is_lemma() << "\n";
for (literal l : *cls) {
display_literal(out, l);
@ -152,20 +164,28 @@ namespace smt {
<< ", ilvl: " << get_intern_level(l.var()) << ", var: " << l.var() << "\n"
<< mk_pp(bool_var2expr(l.var()), m_manager) << "\n\n";
}
return out;
}
void context::display_clause(std::ostream & out, clause const * cls) const {
cls->display_smt2(out, m_manager, m_bool_var2expr.c_ptr());
std::ostream& context::display_clause(std::ostream & out, clause const * cls) const {
cls->display_compact(out, m_manager, m_bool_var2expr.c_ptr());
return out;
}
void context::display_clauses(std::ostream & out, ptr_vector<clause> const & v) const {
std::ostream& context::display_clause_smt2(std::ostream & out, clause const& cls) const {
cls.display_smt2(out, m_manager, m_bool_var2expr.c_ptr());
return out;
}
std::ostream& context::display_clauses(std::ostream & out, ptr_vector<clause> const & v) const {
for (clause* cp : v) {
display_clause(out, cp);
display_clause_smt2(out, *cp);
out << "\n";
}
return out;
}
void context::display_binary_clauses(std::ostream & out) const {
std::ostream& context::display_binary_clauses(std::ostream & out) const {
bool first = true;
unsigned l_idx = 0;
for (watch_list const& wl : m_watches) {
@ -195,6 +215,7 @@ namespace smt {
}
}
}
return out;
}
void context::display_assignment(std::ostream & out) const {

View file

@ -1339,7 +1339,8 @@ namespace smt {
default:
break;
}
TRACE("mk_clause", tout << "after simplification:\n"; display_literals(tout, num_lits, lits); tout << "\n";);
TRACE("mk_clause", tout << "after simplification:\n"; display_literals_verbose(tout, num_lits, lits) << "\n";);
TRACE("mk_clause", tout << "after simplification:\n"; display_literals_smt2(tout, num_lits, lits););
unsigned activity = 0;
if (activity == 0)
activity = 1;

View file

@ -276,13 +276,11 @@ namespace smt {
// ----------------------------------------------------
//
// Model validation (-vldt flag)
// Model validation
//
// ----------------------------------------------------
virtual bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const {
return true;
}
virtual void validate_model(model& mdl) {}
// ----------------------------------------------------
//

View file

@ -682,8 +682,6 @@ namespace smt {
void flush_eh() override;
void reset_eh() override;
bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override;
// -----------------------------------
//
// bool_var -> atom mapping

View file

@ -1650,11 +1650,6 @@ namespace smt {
theory::reset_eh();
}
template<typename Ext>
bool theory_arith<Ext>::validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const {
return true;
}
/**
\brief Compute the value of a base or quasi-base variable using
the value of the dependent variables.

View file

@ -241,8 +241,6 @@ namespace smt {
bool dump_lemmas() const { return m_params.m_arith_dump_lemmas; }
bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override;
void display(std::ostream & out) const override;
virtual void display_atom(std::ostream & out, atom * a) const;
void collect_statistics(::statistics & st) const override;

View file

@ -425,11 +425,6 @@ namespace smt {
theory::reset_eh();
}
template<typename Ext>
bool theory_dense_diff_logic<Ext>::validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const {
return is_true ? m_assignment[v1] == m_assignment[v2] : m_assignment[v1] != m_assignment[v2];
}
/**
\brief Store in results the antecedents that justify that the distance between source and target.
*/

View file

@ -307,8 +307,6 @@ namespace smt {
void init_model(model_generator & m) override;
model_value_proc * mk_value(enode * n, model_generator & mg) override;
bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override;
void display(std::ostream & out) const override;

View file

@ -911,12 +911,6 @@ model_value_proc * theory_diff_logic<Ext>::mk_value(enode * n, model_generator &
return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, m_util.is_int(n->get_owner())));
}
template<typename Ext>
bool theory_diff_logic<Ext>::validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const {
NOT_IMPLEMENTED_YET();
return true;
}
template<typename Ext>
void theory_diff_logic<Ext>::display(std::ostream & out) const {

View file

@ -3206,12 +3206,6 @@ public:
return false;
}
bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const {
SASSERT(v1 != null_theory_var);
SASSERT(v2 != null_theory_var);
return (get_value(v1) == get_value(v2)) == is_true;
}
// Auxiliary verification utilities.
struct scoped_arith_mode {
@ -3656,10 +3650,6 @@ bool theory_lra::get_lower(enode* n, rational& r, bool& is_strict) {
bool theory_lra::get_upper(enode* n, rational& r, bool& is_strict) {
return m_imp->get_upper(n, r, is_strict);
}
bool theory_lra::validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const {
return m_imp->validate_eq_in_model(v1, v2, is_true);
}
void theory_lra::display(std::ostream & out) const {
m_imp->display(out);
}

View file

@ -85,8 +85,6 @@ namespace smt {
bool get_upper(enode* n, expr_ref& r);
bool get_lower(enode* n, rational& r, bool& is_strict);
bool get_upper(enode* n, rational& r, bool& is_strict);
bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override;
void display(std::ostream & out) const override;

View file

@ -89,7 +89,9 @@ Outline:
#include <typeinfo>
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_trail.h"
#include "ast/for_each_expr.h"
#include "smt/proto_model/value_factory.h"
#include "smt/smt_context.h"
#include "smt/smt_model_generator.h"
@ -138,6 +140,7 @@ void theory_seq::solution_map::update(expr* e, expr* r, dependency* d) {
value.first = r;
value.second = d;
m_map.insert(e, value);
// std::cout << mk_pp(e, m) << " -> " << mk_pp(r, m) << "\n";
add_trail(INS, e, r, d);
}
@ -322,6 +325,14 @@ void theory_seq::init(context* ctx) {
#define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(31, verbose_stream() << s << "\n"); }
struct scoped_enable_trace {
scoped_enable_trace() {
enable_trace("seq");
}
~scoped_enable_trace() {
disable_trace("seq");
}
};
final_check_status theory_seq::final_check_eh() {
if (m_reset_cache) {
@ -402,7 +413,9 @@ final_check_status theory_seq::final_check_eh() {
return FC_CONTINUE;
}
if (is_solved()) {
//scoped_enable_trace _se;
TRACEFIN("is_solved");
TRACE("seq", display(tout););
return FC_DONE;
}
TRACEFIN("give_up");
@ -1024,7 +1037,7 @@ void theory_seq::prop_arith_to_len_offset() {
}
}
int theory_seq::find_fst_non_empty_idx(expr_ref_vector const& xs) const {
int theory_seq::find_fst_non_empty_idx(expr_ref_vector const& xs) {
context & ctx = get_context();
for (unsigned i = 0; i < xs.size(); ++i) {
expr* x = xs[i];
@ -1042,7 +1055,7 @@ int theory_seq::find_fst_non_empty_idx(expr_ref_vector const& xs) const {
return -1;
}
expr* theory_seq::find_fst_non_empty_var(expr_ref_vector const& x) const {
expr* theory_seq::find_fst_non_empty_var(expr_ref_vector const& x) {
int i = find_fst_non_empty_idx(x);
if (i >= 0)
return x[i];
@ -2242,6 +2255,19 @@ bool theory_seq::linearize(dependency* dep, enode_pair_vector& eqs, literal_vect
eqs.push_back(enode_pair(a.n1, a.n2));
}
}
if (!asserted) {
std::cout << "not asserted\n";
context& ctx = get_context();
for (assumption const& a : assumptions) {
if (a.lit != null_literal) {
std::cout << a.lit << " " << ctx.get_assignment(a.lit) << " ";
ctx.display_literal_info(std::cout, a.lit);
ctx.display_detailed_literal(std::cout, a.lit) << "\n";
}
}
// ctx.display(std::cout);
exit(0);
}
return asserted;
}
@ -2308,8 +2334,8 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) {
TRACE("seq", tout << "not linearized\n";);
return;
}
TRACE("seq",
tout << "assert: " << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <-\n";
TRACE("seq_verbose",
tout << "assert: " << mk_bounded_pp(n1->get_owner(), m) << " = " << mk_bounded_pp(n2->get_owner(), m) << " <-\n";
display_deps(tout, dep);
);
@ -2355,15 +2381,44 @@ void theory_seq::enforce_length_coherence(enode* n1, enode* n2) {
}
bool theory_seq::lift_ite(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* deps) {
if (ls.size() != 1 || rs.size() != 1) {
return false;
}
context& ctx = get_context();
expr* c = nullptr, *t = nullptr, *e = nullptr;
expr* l = ls[0], *r = rs[0];
if (m.is_ite(r)) {
std::swap(l, r);
}
if (!m.is_ite(l, c, t, e)) {
return false;
}
switch (ctx.find_assignment(c)) {
case l_undef:
return false;
case l_true:
deps = mk_join(deps, ctx.get_literal(c));
m_eqs.push_back(mk_eqdep(t, r, deps));
return true;
case l_false:
deps = mk_join(deps, ~ctx.get_literal(c));
m_eqs.push_back(mk_eqdep(e, r, deps));
return true;
}
return false;
}
bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependency* deps) {
context& ctx = get_context();
expr_ref_vector lhs(m), rhs(m);
bool changed = false;
TRACE("seq", tout << ls << " = " << rs << "\n";);
TRACE("seq_verbose", tout << ls << " = " << rs << "\n";);
if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs, changed)) {
// equality is inconsistent.
TRACE("seq", tout << ls << " != " << rs << "\n";);
TRACE("seq_verbose", tout << ls << " != " << rs << "\n";);
set_conflict(deps);
return true;
}
@ -2377,7 +2432,7 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc
TRACE("seq", tout << "solved\n";);
return true;
}
TRACE("seq",
TRACE("seq_verbose",
tout << ls << " = " << rs << "\n";
tout << lhs << " = " << rhs << "\n";);
for (unsigned i = 0; !ctx.inconsistent() && i < lhs.size(); ++i) {
@ -2394,7 +2449,7 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc
propagate_eq(deps, ensure_enode(li), ensure_enode(ri));
}
}
TRACE("seq",
TRACE("seq_verbose",
if (!ls.empty() || !rs.empty()) tout << ls << " = " << rs << ";\n";
for (unsigned i = 0; i < lhs.size(); ++i) {
tout << mk_pp(lhs.get(i), m) << " = " << mk_pp(rhs.get(i), m) << ";\n";
@ -2523,6 +2578,7 @@ bool theory_seq::is_var(expr* a) const {
!m_util.str.is_string(a) &&
!m_util.str.is_unit(a) &&
!m_util.str.is_itos(a) &&
!m_util.str.is_nth_i(a) &&
// !m_util.str.is_extract(a) &&
!m.is_ite(a);
}
@ -2560,7 +2616,7 @@ bool theory_seq::solve_eqs(unsigned i) {
m_eqs.pop_back();
change = true;
}
TRACE("seq", display_equations(tout););
TRACE("seq_verbose", display_equations(tout););
}
return change || m_new_propagation || ctx.inconsistent();
}
@ -2574,7 +2630,7 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de
bool change = canonize(l, ls, dep2);
change = canonize(r, rs, dep2) || change;
deps = m_dm.mk_join(dep2, deps);
TRACE("seq", tout << l << " = " << r << " ==> ";
TRACE("seq_verbose", tout << l << " = " << r << " ==> ";
tout << ls << " = " << rs << "\n";
display_deps(tout, deps);
);
@ -2582,7 +2638,10 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de
TRACE("seq", tout << "simplified\n";);
return true;
}
TRACE("seq", tout << ls << " = " << rs << "\n";);
if (!ctx.inconsistent() && lift_ite(ls, rs, deps)) {
return true;
}
TRACE("seq_verbose", tout << ls << " = " << rs << "\n";);
if (ls.empty() && rs.empty()) {
return true;
}
@ -3526,9 +3585,7 @@ bool theory_seq::internalize_term(app* term) {
return true;
}
void theory_seq::add_length(expr* l) {
expr* e = nullptr;
VERIFY(m_util.str.is_length(l, e));
void theory_seq::add_length(expr* e, expr* l) {
SASSERT(!m_length.contains(l));
m_length.push_back(l);
m_has_length.insert(e);
@ -3546,9 +3603,9 @@ void theory_seq::enforce_length(expr* e) {
do {
expr* o = n->get_owner();
if (!has_length(o)) {
expr_ref len = mk_len(o);
expr_ref len(m_util.str.mk_length(o), m);
enque_axiom(len);
add_length(len);
add_length(o, len);
}
n = n->get_next();
}
@ -4119,6 +4176,54 @@ app* theory_seq::mk_value(app* e) {
}
void theory_seq::validate_model(model& mdl) {
std::cout << "validate-seq-model\n";
for (auto const& eq : m_eqs) {
expr_ref_vector ls = eq.ls();
expr_ref_vector rs = eq.rs();
expr_ref l(m_util.str.mk_concat(ls), m);
expr_ref r(m_util.str.mk_concat(rs), m);
if (!mdl.are_equal(l, r)) {
IF_VERBOSE(0, verbose_stream() << l << " = " << r << " but " << mdl(l) << " != " << mdl(r) << "\n");
}
}
for (auto const& ne : m_nqs) {
expr_ref l = ne.l();
expr_ref r = ne.r();
if (mdl.are_equal(l, r)) {
IF_VERBOSE(0, verbose_stream() << l << " = " << r << " = " << mdl(l) << "\n");
}
}
for (auto const& ex : m_exclude) {
expr_ref l(ex.first, m);
expr_ref r(ex.second, m);
if (mdl.are_equal(l, r)) {
IF_VERBOSE(0, verbose_stream() << "exclude " << l << " = " << r << " = " << mdl(l) << "\n");
}
}
for (auto const& nc : m_ncs) {
expr_ref p = nc.contains();
if (!mdl.is_false(p)) {
IF_VERBOSE(0, verbose_stream() << p << " evaluates to " << mdl(p) << "\n");
}
}
#if 0
ptr_vector<expr> fmls;
context& ctx = get_context();
ctx.get_asserted_formulas(fmls);
validate_model_proc proc(*this, mdl);
for (expr* f : fmls) {
for_each_expr(proc, f);
}
#endif
}
theory_var theory_seq::mk_var(enode* n) {
if (!m_util.is_seq(n->get_owner()) &&
!m_util.is_re(n->get_owner())) {
@ -4385,9 +4490,8 @@ void theory_seq::propagate() {
}
void theory_seq::enque_axiom(expr* e) {
TRACE("seq", tout << "enqueue_axiom " << mk_pp(e, m) << " " << m_axiom_set.contains(e) << "\n";);
if (!m_axiom_set.contains(e)) {
TRACE("seq", tout << "add axiom " << mk_pp(e, m) << "\n";);
TRACE("seq", tout << "add axiom " << mk_bounded_pp(e, m) << "\n";);
m_axioms.push_back(e);
m_axiom_set.insert(e);
m_trail_stack.push(push_back_vector<theory_seq, expr_ref_vector>(m_axioms));
@ -4436,6 +4540,9 @@ void theory_seq::deque_axiom(expr* n) {
else if (m_util.str.is_le(n)) {
add_le_axiom(n);
}
else if (m_util.str.is_unit(n)) {
add_unit_axiom(n);
}
}
@ -4843,6 +4950,13 @@ expr_ref theory_seq::mk_add(expr* a, expr* b) {
return result;
}
expr_ref theory_seq::mk_len(expr* s) {
expr_ref result(m_util.str.mk_length(s), m);
m_rewrite(result);
return result;
}
enode* theory_seq::ensure_enode(expr* e) {
context& ctx = get_context();
if (!ctx.e_internalized(e)) {
@ -4924,7 +5038,7 @@ bool theory_seq::lower_bound2(expr* _e, rational& lo) {
}
bool theory_seq::get_length(expr* e, rational& val) const {
bool theory_seq::get_length(expr* e, rational& val) {
rational val1;
expr_ref len(m), len_val(m);
expr* e1 = nullptr, *e2 = nullptr;
@ -4992,11 +5106,11 @@ this translates to:
*/
void theory_seq::add_extract_axiom(expr* e) {
TRACE("seq", tout << mk_pp(e, m) << "\n";);
expr* s = nullptr, *i = nullptr, *l = nullptr;
VERIFY(m_util.str.is_extract(e, s, i, l));
#if 0
if (is_tail(s, i, l)) {
add_tail_axiom(e, s);
return;
@ -5013,7 +5127,6 @@ void theory_seq::add_extract_axiom(expr* e) {
add_extract_suffix_axiom(e, s, i);
return;
}
#endif
expr_ref x(mk_skolem(m_pre, s, i), m);
expr_ref ls = mk_len(s);
expr_ref lx = mk_len(x);
@ -5033,6 +5146,7 @@ void theory_seq::add_extract_axiom(expr* e) {
literal ls_le_0 = mk_simplified_literal(m_autil.mk_le(ls, zero));
literal le_is_0 = mk_eq(le, zero, false);
add_axiom(~i_ge_0, ~i_le_ls, mk_seq_eq(xey, s));
add_axiom(~i_ge_0, ~i_le_ls, mk_eq(lx, i, false));
add_axiom(~i_ge_0, ~i_le_ls, ~l_ge_0, ~li_ge_ls, mk_eq(le, l, false));
@ -5156,7 +5270,7 @@ void theory_seq::add_at_axiom(expr* e) {
literal i_ge_len_s = mk_simplified_literal(m_autil.mk_ge(mk_sub(i, mk_len(s)), zero));
rational iv;
if (m_autil.is_numeral(i, iv) && iv.is_int() && !iv.is_neg()) {
if (m_autil.is_numeral(i, iv) && iv.is_unsigned()) {
expr_ref_vector es(m);
expr_ref nth(m);
unsigned k = iv.get_unsigned();
@ -5183,6 +5297,12 @@ void theory_seq::add_at_axiom(expr* e) {
add_axiom(~i_ge_len_s, mk_eq(e, emp, false));
}
/**
\brief
i >= 0 i < len(s) => unit(nth_i(s, i)) = at(s, i)
nth_i(unit(nth_i(s, i)), 0) = nth_i(s, i)
*/
void theory_seq::add_nth_axiom(expr* e) {
expr* s = nullptr, *i = nullptr;
rational n;
@ -5194,12 +5314,19 @@ void theory_seq::add_nth_axiom(expr* e) {
}
else {
expr_ref zero(m_autil.mk_int(0), m);
literal i_ge_0 = mk_simplified_literal(m_autil.mk_ge(i, zero));
literal i_ge_0 = mk_simplified_literal(m_autil.mk_ge(i, zero));
literal i_ge_len_s = mk_simplified_literal(m_autil.mk_ge(mk_sub(i, mk_len(s)), zero));
// at(s,i) = [nth(s,i)]
expr_ref rhs(s, m);
if (!m_util.str.is_at(s)) rhs = m_util.str.mk_at(s, i);
add_axiom(~i_ge_0, i_ge_len_s, mk_eq(m_util.str.mk_unit(e), rhs, false));
expr_ref lhs(m_util.str.mk_unit(e), m);
if (!m_util.str.is_at(s) || zero != i) rhs = m_util.str.mk_at(s, i);
if (e->get_id() == 420) {
enable_trace("seq");
}
add_axiom(~i_ge_0, i_ge_len_s, mk_eq(lhs, rhs, false));
if (e->get_id() == 420) {
disable_trace("seq");
}
}
}
@ -5308,7 +5435,14 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4, liter
log_axiom_instantiation(body);
}
ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
if (m.has_trace_stream()) m.trace_stream() << "[end-of-instance]\n";
if (m.has_trace_stream()) {
m.trace_stream() << "[end-of-instance]\n";
}
if (!ctx.at_base_level() && l2 == null_literal) {
m_trail_stack.push(push_replay(alloc(replay_unit_literal, m, ctx.bool_var2expr(l1.var()), l1.sign())));
}
}
@ -5449,14 +5583,13 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
expr* e1 = nullptr, *e2 = nullptr;
expr_ref f(m);
literal lit(v, !is_true);
TRACE("seq", tout << (is_true?"":"not ") << mk_pp(e, m) << "\n";);
if (m_util.str.is_prefix(e, e1, e2)) {
if (is_true) {
f = mk_skolem(m_prefix, e1, e2);
f = mk_concat(e1, f);
propagate_eq(lit, f, e2, true);
//literal len1_le_len2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e2), mk_len(e1)), m_autil.mk_int(0)));
//add_axiom(~lit, len1_le_len2);
}
else {
propagate_not_prefix(e);
@ -5467,8 +5600,6 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
f = mk_skolem(m_suffix, e1, e2);
f = mk_concat(f, e1);
propagate_eq(lit, f, e2, true);
//literal len1_le_len2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e2), mk_len(e1)), m_autil.mk_int(0)));
//add_axiom(~lit, len1_le_len2);
}
else {
propagate_not_suffix(e);
@ -5580,7 +5711,7 @@ lbool theory_seq::regex_are_equal(expr* r1, expr* r2) {
void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
TRACE("seq", tout << expr_ref(n1->get_owner(), m) << " = " << expr_ref(n2->get_owner(), m) << "\n";);
TRACE("seq", tout << mk_bounded_pp(n1->get_owner(), m) << " = " << mk_bounded_pp(n2->get_owner(), m) << "\n";);
if (n1 != n2 && m_util.is_seq(n1->get_owner())) {
theory_var v1 = n1->get_th_var(get_id());
theory_var v2 = n2->get_th_var(get_id());
@ -5590,7 +5721,7 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
m_find.merge(v1, v2);
expr_ref o1(n1->get_owner(), m);
expr_ref o2(n2->get_owner(), m);
TRACE("seq", tout << o1 << " = " << o2 << "\n";);
TRACE("seq", tout << mk_bounded_pp(o1, m) << " = " << mk_bounded_pp(o2, m) << "\n";);
m_eqs.push_back(mk_eqdep(o1, o2, deps));
solve_eqs(m_eqs.size()-1);
enforce_length_coherence(n1, n2);
@ -5651,14 +5782,16 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {
m_rewrite(eq);
if (!m.is_false(eq)) {
literal lit = mk_eq(e1, e2, false);
get_context().mark_as_relevant(lit);
if (m_util.str.is_empty(e2)) {
std::swap(e1, e2);
}
dependency* dep = m_dm.mk_leaf(assumption(~lit));
m_nqs.push_back(ne(e1, e2, dep));
solve_nqs(m_nqs.size() - 1);
if (get_context().get_assignment(lit) != l_undef) {
solve_nqs(m_nqs.size() - 1);
}
}
}
@ -5700,6 +5833,7 @@ void theory_seq::restart_eh() {
}
void theory_seq::relevant_eh(app* n) {
TRACE("seq", tout << mk_pp(n, m) << "\n";);
if (m_util.str.is_index(n) ||
m_util.str.is_replace(n) ||
m_util.str.is_extract(n) ||
@ -5710,6 +5844,7 @@ void theory_seq::relevant_eh(app* n) {
m_util.str.is_itos(n) ||
m_util.str.is_stoi(n) ||
m_util.str.is_lt(n) ||
m_util.str.is_unit(n) ||
m_util.str.is_le(n)) {
enque_axiom(n);
}
@ -5922,9 +6057,6 @@ void theory_seq::propagate_not_prefix(expr* e) {
VERIFY(m_util.str.is_prefix(e, e1, e2));
literal lit = ctx.get_literal(e);
SASSERT(ctx.get_assignment(lit) == l_false);
if (canonizes(false, e)) {
return;
}
propagate_non_empty(~lit, e1);
literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), m_autil.mk_int(1)));
sort* char_sort = nullptr;
@ -5951,9 +6083,6 @@ void theory_seq::propagate_not_suffix(expr* e) {
VERIFY(m_util.str.is_suffix(e, e1, e2));
literal lit = ctx.get_literal(e);
SASSERT(ctx.get_assignment(lit) == l_false);
if (canonizes(false, e)) {
return;
}
propagate_non_empty(~lit, e1);
literal e1_gt_e2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), m_autil.mk_int(1)));
sort* char_sort = nullptr;
@ -5968,6 +6097,14 @@ void theory_seq::propagate_not_suffix(expr* e) {
add_axiom(lit, e1_gt_e2, ~mk_eq(c, d, false));
}
void theory_seq::add_unit_axiom(expr* n) {
expr* u = nullptr;
VERIFY(m_util.str.is_unit(n, u));
sort* s = m.get_sort(u);
expr_ref rhs(mk_skolem(symbol("inv-unit"), n, nullptr, nullptr, nullptr, s), m);
add_axiom(mk_eq(u, rhs, false));
}
/**
e1 < e2 => e1 = empty or e1 = xcy
e1 < e2 => e1 = empty or c < d

View file

@ -50,6 +50,7 @@ namespace smt {
typedef union_find<theory_seq> th_union_find;
class seq_value_proc;
struct validate_model_proc;
// cache to track evaluations under equalities
class eval_cache {
@ -97,7 +98,9 @@ namespace smt {
// Table of current disequalities
class exclusion_table {
public:
typedef obj_pair_hashtable<expr, expr> table_t;
protected:
ast_manager& m;
table_t m_table;
expr_ref_vector m_lhs, m_rhs;
@ -111,6 +114,8 @@ namespace smt {
void push_scope() { m_limit.push_back(m_lhs.size()); }
void pop_scope(unsigned num_scopes);
void display(std::ostream& out) const;
table_t::iterator begin() const { return m_table.begin(); }
table_t::iterator end() const { return m_table.end(); }
};
// Asserted or derived equality with dependencies
@ -260,6 +265,20 @@ namespace smt {
}
};
class replay_unit_literal : public apply {
bool m_sign;
expr_ref m_e;
public:
replay_unit_literal(ast_manager& m, expr* e, bool sign) : m_e(e, m), m_sign(sign) {}
~replay_unit_literal() override {}
void operator()(theory_seq& th) override {
literal lit = th.mk_literal(m_e);
if (m_sign) lit.neg();
th.add_axiom(lit);
m_e.reset();
}
};
class replay_is_axiom : public apply {
expr_ref m_e;
@ -290,6 +309,7 @@ namespace smt {
}
};
struct s_in_re {
literal m_lit;
expr* m_s;
@ -404,6 +424,7 @@ namespace smt {
void init_model(model_generator & mg) override;
void finalize_model(model_generator & mg) override;
void init_search_eh() override;
void validate_model(model& mdl) override;
void init_model(expr_ref_vector const& es);
app* get_ite_value(expr* a);
@ -411,8 +432,8 @@ namespace smt {
void len_offset(expr* e, rational val);
void prop_arith_to_len_offset();
int find_fst_non_empty_idx(expr_ref_vector const& x) const;
expr* find_fst_non_empty_var(expr_ref_vector const& x) const;
int find_fst_non_empty_idx(expr_ref_vector const& x);
expr* find_fst_non_empty_var(expr_ref_vector const& x);
void find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector const& rs);
bool has_len_offset(expr_ref_vector const& ls, expr_ref_vector const& rs, int & diff);
bool find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned idx, dependency*& deps, expr_ref_vector & res);
@ -462,6 +483,7 @@ namespace smt {
bool solve_eqs(unsigned start);
bool solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep, unsigned idx);
bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep);
bool lift_ite(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep);
bool solve_unit_eq(expr* l, expr* r, dependency* dep);
bool solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep);
bool solve_nth_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep);
@ -566,7 +588,7 @@ namespace smt {
bool has_length(expr *e) const { return m_has_length.contains(e); }
void add_length(expr* e);
void add_length(expr* e, expr* l);
void enforce_length(expr* n);
bool enforce_length(expr_ref_vector const& es, vector<rational>& len);
void enforce_length_coherence(enode* n1, enode* n2);
@ -580,6 +602,7 @@ namespace smt {
void add_at_axiom(expr* n);
void add_lt_axiom(expr* n);
void add_le_axiom(expr* n);
void add_unit_axiom(expr* n);
void add_nth_axiom(expr* n);
void add_in_re_axiom(expr* n);
void add_itos_axiom(expr* n);
@ -599,7 +622,7 @@ namespace smt {
void tightest_prefix(expr* s, expr* x);
expr_ref mk_sub(expr* a, expr* b);
expr_ref mk_add(expr* a, expr* b);
expr_ref mk_len(expr* s) const { return expr_ref(m_util.str.mk_length(s), m); }
expr_ref mk_len(expr* s);
enode* ensure_enode(expr* a);
enode* get_root(expr* a) { return ensure_enode(a)->get_root(); }
dependency* mk_join(dependency* deps, literal lit);
@ -611,7 +634,7 @@ namespace smt {
bool lower_bound(expr* s, rational& lo) const;
bool lower_bound2(expr* s, rational& lo);
bool upper_bound(expr* s, rational& hi) const;
bool get_length(expr* s, rational& val) const;
bool get_length(expr* s, rational& val);
void mk_decompose(expr* e, expr_ref& head, expr_ref& tail);
expr_ref coalesce_chars(expr* const& str);

View file

@ -250,10 +250,6 @@ namespace smt {
void init_model(model_generator & m) override;
model_value_proc * mk_value(enode * n, model_generator & mg) override;
bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const override {
return true;
}
void display(std::ostream & out) const override;