3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 18:31:49 +00:00

perf improvements for #1979

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-12-04 10:13:55 -08:00
parent ea0d253308
commit 9e5aaf074e
3 changed files with 149 additions and 82 deletions

View file

@ -33,20 +33,23 @@ Notes:
expr_ref sym_expr::accept(expr* e) {
ast_manager& m = m_t.get_manager();
expr_ref result(m);
var_subst subst(m);
seq_util u(m);
unsigned r1, r2, r3;
switch (m_ty) {
case t_pred: {
var_subst subst(m);
case t_pred:
result = subst(m_t, 1, &e);
break;
case t_not:
result = m_expr->accept(e);
result = m.mk_not(result);
break;
}
case t_char:
SASSERT(m.get_sort(e) == m.get_sort(m_t));
SASSERT(m.get_sort(e) == m_sort);
result = m.mk_eq(e, m_t);
break;
case t_range: {
seq_util u(m);
unsigned r1, r2, r3;
case t_range:
if (u.is_const_char(m_t, r1) && u.is_const_char(e, r2) && u.is_const_char(m_s, r3)) {
result = m.mk_bool_val((r1 <= r2) && (r2 <= r3));
}
@ -55,7 +58,7 @@ expr_ref sym_expr::accept(expr* e) {
}
break;
}
}
return result;
}
@ -64,6 +67,7 @@ std::ostream& sym_expr::display(std::ostream& out) const {
case t_char: return out << m_t;
case t_range: return out << m_t << ":" << m_s;
case t_pred: return out << m_t;
case t_not: return m_expr->display(out << "not ");
}
return out << "expression type not recognized";
}
@ -79,10 +83,11 @@ struct display_expr1 {
class sym_expr_boolean_algebra : public boolean_algebra<sym_expr*> {
ast_manager& m;
expr_solver& m_solver;
expr_ref m_var;
typedef sym_expr* T;
public:
sym_expr_boolean_algebra(ast_manager& m, expr_solver& s):
m(m), m_solver(s) {}
m(m), m_solver(s), m_var(m) {}
T mk_false() override {
expr_ref fml(m.mk_false(), m);
@ -93,6 +98,7 @@ public:
return sym_expr::mk_pred(fml, m.mk_bool_sort());
}
T mk_and(T x, T y) override {
seq_util u(m);
if (x->is_char() && y->is_char()) {
if (x->get_char() == y->get_char()) {
return x;
@ -102,6 +108,21 @@ public:
return sym_expr::mk_pred(fml, x->get_sort());
}
}
unsigned lo1, hi1, lo2, hi2;
if (x->is_range() && y->is_range() &&
u.is_const_char(x->get_lo(), lo1) && u.is_const_char(x->get_hi(), hi1) &&
u.is_const_char(y->get_lo(), lo2) && u.is_const_char(y->get_hi(), hi2)) {
lo1 = std::max(lo1, lo2);
hi1 = std::min(hi1, hi2);
if (lo1 > hi1) {
expr_ref fml(m.mk_false(), m);
return sym_expr::mk_pred(fml, x->get_sort());
}
expr_ref _start(u.mk_char(lo1), m);
expr_ref _stop(u.mk_char(hi1), m);
return sym_expr::mk_range(_start, _stop);
}
sort* s = x->get_sort();
if (m.is_bool(s)) s = y->get_sort();
var_ref v(m.mk_var(0, s), m);
@ -110,13 +131,29 @@ public:
if (m.is_true(fml1)) {
return y;
}
if (m.is_true(fml2)) return x;
if (fml1 == fml2) return x;
if (m.is_true(fml2)) {
return x;
}
if (fml1 == fml2) {
return x;
}
if (is_complement(fml1, fml2)) {
expr_ref ff(m.mk_false(), m);
return sym_expr::mk_pred(ff, x->get_sort());
}
bool_rewriter br(m);
expr_ref fml(m);
br.mk_and(fml1, fml2, fml);
return sym_expr::mk_pred(fml, x->get_sort());
}
bool is_complement(expr* f1, expr* f2) {
expr* f = nullptr;
return
(m.is_not(f1, f) && f == f2) ||
(m.is_not(f2, f) && f == f1);
}
T mk_or(T x, T y) override {
if (x->is_char() && y->is_char() &&
x->get_char() == y->get_char()) {
@ -147,6 +184,7 @@ public:
}
}
}
T mk_or(unsigned sz, T const* ts) override {
switch (sz) {
case 0: return mk_false();
@ -160,15 +198,24 @@ public:
}
}
}
lbool is_sat(T x) override {
unsigned lo, hi;
seq_util u(m);
if (x->is_char()) {
return l_true;
}
if (x->is_range()) {
// TBD check lower is below upper.
if (x->is_range() && u.is_const_char(x->get_lo(), lo) && u.is_const_char(x->get_hi(), hi)) {
return (lo <= hi) ? l_true : l_false;
}
expr_ref v(m.mk_fresh_const("x", x->get_sort()), m);
expr_ref fml = x->accept(v);
if (x->is_not() && x->get_arg()->is_range() && u.is_const_char(x->get_arg()->get_lo(), lo) && 0 < lo) {
return l_true;
}
if (!m_var || m.get_sort(m_var) != x->get_sort()) {
m_var = m.mk_fresh_const("x", x->get_sort());
}
expr_ref fml = x->accept(m_var);
if (m.is_true(fml)) {
return l_true;
}
@ -177,16 +224,11 @@ public:
}
return m_solver.check_sat(fml);
}
T mk_not(T x) override {
var_ref v(m.mk_var(0, x->get_sort()), m);
expr_ref fml(m.mk_not(x->accept(v)), m);
return sym_expr::mk_pred(fml, x->get_sort());
return sym_expr::mk_not(m, x);
}
/*virtual vector<std::pair<vector<bool>, T>> generate_min_terms(vector<T> constraints){
return 0;
}*/
};
re2automaton::re2automaton(ast_manager& m): m(m), u(m), m_ba(nullptr), m_sa(nullptr) {}
@ -1434,6 +1476,14 @@ br_status seq_rewriter::mk_re_inter(expr* a, expr* b, expr_ref& result) {
result = a;
return BR_DONE;
}
expr* ac = nullptr, *bc = nullptr;
if ((m_util.re.is_complement(a, ac) && ac == b) ||
(m_util.re.is_complement(b, bc) && bc == a)) {
sort* seq_sort = nullptr;
VERIFY(m_util.is_re(a, seq_sort));
result = m_util.re.mk_empty(seq_sort);
return BR_DONE;
}
return BR_FAILED;
}

View file

@ -31,31 +31,38 @@ class sym_expr {
enum ty {
t_char,
t_pred,
t_not,
t_range
};
ty m_ty;
sort* m_sort;
expr_ref m_t;
expr_ref m_s;
unsigned m_ref;
sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt) : m_ty(ty), m_sort(srt), m_t(t), m_s(s), m_ref(0) {}
ty m_ty;
sort* m_sort;
sym_expr* m_expr;
expr_ref m_t;
expr_ref m_s;
unsigned m_ref;
sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt, sym_expr* e) :
m_ty(ty), m_sort(srt), m_expr(e), m_t(t), m_s(s), m_ref(0) {}
public:
~sym_expr() { if (m_expr) m_expr->dec_ref(); }
expr_ref accept(expr* e);
static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t)); }
static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t), nullptr); }
static sym_expr* mk_char(ast_manager& m, expr* t) { expr_ref tr(t, m); return mk_char(tr); }
static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s); }
static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi)); }
static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s, nullptr); }
static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi), nullptr); }
static sym_expr* mk_not(ast_manager& m, sym_expr* e) { expr_ref f(m); e->inc_ref(); return alloc(sym_expr, t_not, f, f, e->get_sort(), e); }
void inc_ref() { ++m_ref; }
void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); }
std::ostream& display(std::ostream& out) const;
bool is_char() const { return m_ty == t_char; }
bool is_pred() const { return !is_char(); }
bool is_range() const { return m_ty == t_range; }
bool is_not() const { return m_ty == t_not; }
sort* get_sort() const { return m_sort; }
expr* get_char() const { SASSERT(is_char()); return m_t; }
expr* get_pred() const { SASSERT(is_pred()); return m_t; }
expr* get_lo() const { SASSERT(is_range()); return m_t; }
expr* get_hi() const { SASSERT(is_range()); return m_s; }
sym_expr* get_arg() const { SASSERT(is_not()); return m_expr; }
};
class sym_expr_manager {

View file

@ -51,6 +51,7 @@ public:
m_kernel.assert_expr(e);
lbool r = m_kernel.check();
m_kernel.pop(1);
IF_VERBOSE(11, verbose_stream() << "is " << r << " " << mk_pp(e, m_kernel.m()) << "\n");
return r;
}
};
@ -250,6 +251,9 @@ void theory_seq::init(context* ctx) {
m_arith_value.init(ctx);
}
#define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(10, verbose_stream() << s << "\n"); }
final_check_status theory_seq::final_check_eh() {
if (m_reset_cache) {
m_rep.reset_cache();
@ -260,79 +264,79 @@ final_check_status theory_seq::final_check_eh() {
TRACE("seq_verbose", get_context().display(tout););
if (simplify_and_solve_eqs()) {
++m_stats.m_solve_eqs;
TRACE("seq", tout << ">>solve_eqs\n";);
TRACEFIN("solve_eqs");
return FC_CONTINUE;
}
if (check_contains()) {
++m_stats.m_propagate_contains;
TRACE("seq", tout << ">>propagate_contains\n";);
TRACEFIN("propagate_contains");
return FC_CONTINUE;
}
if (solve_nqs(0)) {
++m_stats.m_solve_nqs;
TRACE("seq", tout << ">>solve_nqs\n";);
TRACEFIN("solve_nqs");
return FC_CONTINUE;
}
if (fixed_length(true)) {
++m_stats.m_fixed_length;
TRACE("seq", tout << ">>zero_length\n";);
TRACEFIN("zero_length");
return FC_CONTINUE;
}
if (m_params.m_split_w_len && len_based_split()) {
++m_stats.m_branch_variable;
TRACE("seq", tout << ">>split_based_on_length\n";);
TRACEFIN("split_based_on_length");
return FC_CONTINUE;
}
if (fixed_length()) {
++m_stats.m_fixed_length;
TRACE("seq", tout << ">>fixed_length\n";);
TRACEFIN("fixed_length");
return FC_CONTINUE;
}
if (check_int_string()) {
++m_stats.m_int_string;
TRACE("seq", tout << ">>int_string\n";);
TRACEFIN("int_string");
return FC_CONTINUE;
}
if (reduce_length_eq()) {
++m_stats.m_branch_variable;
TRACE("seq", tout << ">>reduce length\n";);
TRACEFIN("reduce_length");
return FC_CONTINUE;
}
if (branch_unit_variable()) {
++m_stats.m_branch_variable;
TRACE("seq", tout << ">>branch_unit_variable\n";);
TRACEFIN("ranch_unit_variable");
return FC_CONTINUE;
}
if (branch_binary_variable()) {
++m_stats.m_branch_variable;
TRACE("seq", tout << ">>branch_binary_variable\n";);
TRACEFIN("branch_binary_variable");
return FC_CONTINUE;
}
if (branch_ternary_variable1() || branch_ternary_variable2() || branch_quat_variable()) {
++m_stats.m_branch_variable;
TRACE("seq", tout << ">>split_based_on_alignment\n";);
TRACEFIN("split_based_on_alignment");
return FC_CONTINUE;
}
if (branch_variable_mb() || branch_variable()) {
++m_stats.m_branch_variable;
TRACE("seq", tout << ">>branch_variable\n";);
TRACEFIN("branch_variable");
return FC_CONTINUE;
}
if (check_length_coherence()) {
++m_stats.m_check_length_coherence;
TRACE("seq", tout << ">>check_length_coherence\n";);
TRACEFIN("check_length_coherence");
return FC_CONTINUE;
}
if (!check_extensionality()) {
++m_stats.m_extensionality;
TRACE("seq", tout << ">>extensionality\n";);
TRACEFIN("extensionality");
return FC_CONTINUE;
}
if (is_solved()) {
TRACE("seq", tout << ">>is_solved\n";);
TRACEFIN("is_solved");
return FC_DONE;
}
TRACE("seq", tout << ">>give_up\n";);
TRACEFIN("give_up");
return FC_GIVEUP;
}
@ -4518,8 +4522,6 @@ void theory_seq::add_itos_length_axiom(expr* len) {
void theory_seq::propagate_in_re(expr* n, bool is_true) {
TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";);
expr* s = nullptr, *re = nullptr;
VERIFY(m_util.str.is_in_re(n, s, re));
expr_ref tmp(n, m);
m_rewrite(tmp);
@ -4540,43 +4542,39 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) {
return;
}
expr_ref e3(re, m);
expr* s = nullptr, *_re = nullptr;
VERIFY(m_util.str.is_in_re(n, s, _re));
expr_ref re(_re, m);
context& ctx = get_context();
literal lit = ctx.get_literal(n);
if (!is_true) {
e3 = m_util.re.mk_complement(re);
re = m_util.re.mk_complement(re);
lit.neg();
}
literal_vector lits;
enode_pair_vector eqs;
literal_vector lits;
for (unsigned i = 0; i < m_s_in_re.size(); ++i) {
auto const& entry = m_s_in_re[i];
if (entry.m_active && get_root(entry.m_s) == get_root(s)) {
if (entry.m_active && get_root(entry.m_s) == get_root(s) && entry.m_re != re) {
m_trail_stack.push(vector_value_trail<theory_seq, s_in_re, true>(m_s_in_re, i));
m_s_in_re[i].m_active = false;
e3 = m_util.re.mk_inter(entry.m_re, e3);
IF_VERBOSE(11, verbose_stream() << "intersect " << re << " " << mk_pp(entry.m_re, m) << " " << mk_pp(s, m) << " " << mk_pp(entry.m_s, m) << "\n";);
re = m_util.re.mk_inter(entry.m_re, re);
m_rewrite(re);
lits.push_back(entry.m_lit);
eqs.push_back(enode_pair(ensure_enode(entry.m_s), ensure_enode(s)));
enode* n1 = ensure_enode(entry.m_s);
enode* n2 = ensure_enode(s);
if (n1 != n2) {
lits.push_back(mk_eq(n1->get_owner(), n2->get_owner(), false));
}
}
}
if (!lits.empty()) {
TRACE("seq", tout << "creating intersection " << e3 << "\n";);
lits.push_back(lit);
literal inter = mk_literal(m_util.re.mk_in_re(s, e3));
justification* js =
ctx.mk_justification(
ext_theory_propagation_justification(
get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), inter));
ctx.assign(inter, js);
return;
}
eautomaton* a = get_automaton(e3);
IF_VERBOSE(11, verbose_stream() << mk_pp(s, m) << " in " << re << "\n");
eautomaton* a = get_automaton(re);
if (!a) return;
m_s_in_re.push_back(s_in_re(lit, s, e3, a));
m_s_in_re.push_back(s_in_re(lit, s, re, a));
m_trail_stack.push(push_back_vector<theory_seq, vector<s_in_re>>(m_s_in_re));
expr_ref len = mk_len(s);
@ -4587,7 +4585,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) {
lits.push_back(~lit);
for (unsigned st : states) {
lits.push_back(mk_accept(s, zero, e3, st));
lits.push_back(mk_accept(s, zero, re, st));
}
if (lits.size() == 2) {
propagate_lit(nullptr, 1, &lit, lits[1]);
@ -4906,24 +4904,36 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) {
void theory_seq::add_at_axiom(expr* e) {
expr* s = nullptr, *i = nullptr;
VERIFY(m_util.str.is_at(e, s, i));
expr_ref len_e = mk_len(e);
expr_ref len_s = mk_len(s);
expr_ref zero(m_autil.mk_int(0), m);
expr_ref one(m_autil.mk_int(1), m);
expr_ref x = mk_skolem(m_pre, s, i);
//expr_ref y = mk_skolem(m_post, s, mk_sub(mk_sub(len_s, i), one));
expr_ref y = mk_skolem(m_tail, s, i);
expr_ref xey = mk_concat(x, e, y);
expr_ref len_x = mk_len(x);
expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
expr_ref len_s = mk_len(s);
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));
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));
rational iv;
if (m_autil.is_numeral(i, iv) && iv.is_int() && !iv.is_neg()) {
expr_ref_vector es(m);
expr_ref nth(m);
unsigned k = iv.get_unsigned();
for (unsigned j = 0; j <= k; ++j) {
es.push_back(m_util.str.mk_unit(mk_nth(s, m_autil.mk_int(j))));
}
nth = es.back();
es.push_back(mk_skolem(m_tail, s, m_autil.mk_int(k)));
add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(s, m_util.str.mk_concat(es)));
add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(nth, e));
}
else {
expr_ref len_e = mk_len(e);
expr_ref x = mk_skolem(m_pre, s, i);
expr_ref y = mk_skolem(m_tail, s, i);
expr_ref xey = mk_concat(x, e, y);
expr_ref len_x = mk_len(x);
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(e, emp, false));
add_axiom(~i_ge_len_s, mk_eq(e, emp, false));