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:
parent
ea0d253308
commit
9e5aaf074e
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue