mirror of
https://github.com/Z3Prover/z3
synced 2025-08-26 13:06:05 +00:00
merge
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
db3c42b02d
32 changed files with 521 additions and 53 deletions
|
@ -303,7 +303,9 @@ public:
|
|||
}
|
||||
|
||||
void display_bounded(ast * n, unsigned depth) {
|
||||
if (is_app(n)) {
|
||||
if (!n)
|
||||
m_out << "null";
|
||||
else if (is_app(n)) {
|
||||
display(to_expr(n), depth);
|
||||
}
|
||||
else if (is_var(n)) {
|
||||
|
|
|
@ -769,6 +769,67 @@ namespace seq {
|
|||
}
|
||||
}
|
||||
|
||||
void axioms::ubv2s_axiom(expr* b, unsigned k) {
|
||||
expr_ref ge10k(m), ge10k1(m), eq(m);
|
||||
bv_util bv(m);
|
||||
sort* bv_sort = b->get_sort();
|
||||
rational pow(1);
|
||||
for (unsigned i = 0; i < k; ++i)
|
||||
pow *= 10;
|
||||
if (k == 0) {
|
||||
ge10k = m.mk_true();
|
||||
}
|
||||
else {
|
||||
ge10k = bv.mk_ule(bv.mk_numeral(pow, bv_sort), b);
|
||||
}
|
||||
ge10k1 = bv.mk_ule(bv.mk_numeral(pow * 10, bv_sort), b);
|
||||
unsigned sz = bv.get_bv_size(b);
|
||||
expr_ref_vector es(m);
|
||||
expr_ref bb(b, m), ten(bv.mk_numeral(10, sz), m);
|
||||
pow = 1;
|
||||
for (unsigned i = 0; i <= k; ++i) {
|
||||
if (pow > 1)
|
||||
bb = bv.mk_bv_udiv(b, bv.mk_numeral(pow, bv_sort));
|
||||
es.push_back(seq.str.mk_unit(m_sk.mk_ubv2ch(bv.mk_bv_urem(bb, ten))));
|
||||
pow *= 10;
|
||||
}
|
||||
es.reverse();
|
||||
eq = m.mk_eq(seq.str.mk_ubv2s(b), seq.str.mk_concat(es, seq.str.mk_string_sort()));
|
||||
add_clause(~ge10k, ge10k1, eq);
|
||||
}
|
||||
|
||||
/*
|
||||
* len(ubv2s(b)) = k => 10^k-1 <= b < 10^{k} k > 1
|
||||
* len(ubv2s(b)) = 1 => b < 10^{1} k = 1
|
||||
*/
|
||||
void axioms::ubv2s_len_axiom(expr* b, unsigned k) {
|
||||
expr_ref ge10k(m), ge10k1(m), eq(m);
|
||||
bv_util bv(m);
|
||||
sort* bv_sort = b->get_sort();
|
||||
unsigned sz = bv.get_bv_size(bv_sort);
|
||||
rational pow(1);
|
||||
for (unsigned i = 1; i < k; ++i)
|
||||
pow *= 10;
|
||||
if (pow * 10 >= rational::power_of_two(sz))
|
||||
return; // TODO: add conflict when k is too large or avoid overflow bounds and limits
|
||||
ge10k = bv.mk_ule(bv.mk_numeral(pow, bv_sort), b);
|
||||
ge10k1 = bv.mk_ule(bv.mk_numeral(pow * 10, bv_sort), b);
|
||||
eq = m.mk_eq(seq.str.mk_length(seq.str.mk_ubv2s(b)), a.mk_int(k));
|
||||
add_clause(~eq, ~ge10k1);
|
||||
if (k > 1)
|
||||
add_clause(~eq, ge10k);
|
||||
}
|
||||
|
||||
void axioms::ubv2ch_axiom(sort* bv_sort) {
|
||||
bv_util bv(m);
|
||||
expr_ref eq(m);
|
||||
unsigned sz = bv.get_bv_size(bv_sort);
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
eq = m.mk_eq(m_sk.mk_ubv2ch(bv.mk_numeral(i, sz)), seq.mk_char('0' + i));
|
||||
add_clause(eq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Let s := itos(e)
|
||||
|
||||
|
|
|
@ -94,6 +94,9 @@ namespace seq {
|
|||
void stoi_axiom(expr* n);
|
||||
void stoi_axiom(expr* e, unsigned k);
|
||||
void itos_axiom(expr* s, unsigned k);
|
||||
void ubv2s_axiom(expr* b, unsigned k);
|
||||
void ubv2s_len_axiom(expr* b, unsigned k);
|
||||
void ubv2ch_axiom(sort* bv_sort);
|
||||
void lt_axiom(expr* n);
|
||||
void le_axiom(expr* n);
|
||||
void is_digit_axiom(expr* n);
|
||||
|
|
|
@ -16,6 +16,7 @@ Author:
|
|||
--*/
|
||||
|
||||
#include "ast/rewriter/seq_eq_solver.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
|
||||
namespace seq {
|
||||
|
||||
|
@ -37,6 +38,10 @@ namespace seq {
|
|||
return true;
|
||||
if (reduce_itos3(e, r))
|
||||
return true;
|
||||
if (reduce_ubv2s1(e, r))
|
||||
return true;
|
||||
if (reduce_ubv2s2(e, r))
|
||||
return true;
|
||||
if (reduce_binary_eq(e, r))
|
||||
return true;
|
||||
if (reduce_nth_solved(e, r))
|
||||
|
@ -184,8 +189,8 @@ namespace seq {
|
|||
expr_ref digit = m_ax.sk().mk_digit2int(u);
|
||||
add_consequence(m_ax.mk_ge(digit, 1));
|
||||
}
|
||||
expr_ref y(seq.str.mk_concat(e.rs, e.ls[0]->get_sort()), m);
|
||||
ctx.add_solution(e.ls[0], y);
|
||||
expr_ref y(seq.str.mk_concat(es, es[0]->get_sort()), m);
|
||||
ctx.add_solution(seq.str.mk_itos(n), y);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -209,6 +214,105 @@ namespace seq {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* from_ubv(s) == from_ubv(t)
|
||||
* --------------------------
|
||||
* s = t
|
||||
*/
|
||||
|
||||
bool eq_solver::match_ubv2s1(eqr const& e, expr*& a, expr*& b) {
|
||||
return
|
||||
e.ls.size() == 1 && e.rs.size() == 1 &&
|
||||
seq.str.is_ubv2s(e.ls[0], a) && seq.str.is_ubv2s(e.rs[0], b);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eq_solver::reduce_ubv2s1(eqr const& e, eq_ptr& r) {
|
||||
expr* s = nullptr, * t = nullptr;
|
||||
if (!match_ubv2s1(e, s, t))
|
||||
return false;
|
||||
expr_ref eq = mk_eq(s, t);
|
||||
add_consequence(eq);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* bv2s(n) = [d1]+[d2]+...+[dk]
|
||||
* ---------------------------------
|
||||
* n = 10^{k-1}*d1 + ... + dk
|
||||
*
|
||||
* k > 1 => d1 > 0
|
||||
*/
|
||||
bool eq_solver::match_ubv2s2(eqr const& e, expr*& n, expr_ref_vector const*& es) {
|
||||
if (e.ls.size() == 1 && seq.str.is_ubv2s(e.ls[0], n)) {
|
||||
es = &e.rs;
|
||||
return true;
|
||||
}
|
||||
if (e.rs.size() == 1 && seq.str.is_ubv2s(e.rs[0], n)) {
|
||||
es = &e.ls;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eq_solver::reduce_ubv2s2(eqr const& e, eq_ptr& r) {
|
||||
expr* n = nullptr;
|
||||
expr_ref_vector const* _es = nullptr;
|
||||
if (!match_ubv2s2(e, n, _es))
|
||||
return false;
|
||||
|
||||
expr_ref_vector const& es = *_es;
|
||||
if (es.empty()) {
|
||||
set_conflict();
|
||||
return true;
|
||||
}
|
||||
expr* u = nullptr;
|
||||
for (expr* r : es) {
|
||||
if (seq.str.is_unit(r, u)) {
|
||||
expr_ref is_digit = m_ax.is_digit(u);
|
||||
if (!m.is_true(ctx.expr2rep(is_digit)))
|
||||
add_consequence(is_digit);
|
||||
}
|
||||
}
|
||||
if (!all_units(es, 0, es.size()))
|
||||
return false;
|
||||
|
||||
expr_ref num(m);
|
||||
bv_util bv(m);
|
||||
sort* bv_sort = n->get_sort();
|
||||
unsigned sz = bv.get_bv_size(n);
|
||||
if (es.size() > (sz + log2(10)-1)/log2(10)) {
|
||||
set_conflict();
|
||||
return true;
|
||||
}
|
||||
|
||||
for (expr* r : es) {
|
||||
VERIFY(seq.str.is_unit(r, u));
|
||||
expr_ref digit = m_ax.sk().mk_digit2bv(u, bv_sort);
|
||||
if (!num)
|
||||
num = digit;
|
||||
else
|
||||
num = bv.mk_bv_add(bv.mk_bv_mul(bv.mk_numeral(10, sz), num), digit);
|
||||
}
|
||||
|
||||
expr_ref eq(m.mk_eq(n, num), m);
|
||||
m_ax.rewrite(eq);
|
||||
add_consequence(eq);
|
||||
if (es.size() > 1) {
|
||||
VERIFY(seq.str.is_unit(es[0], u));
|
||||
expr_ref digit = m_ax.sk().mk_digit2bv(u, bv_sort);
|
||||
expr_ref eq0(m.mk_eq(digit, bv.mk_numeral(0, sz)), m);
|
||||
expr_ref neq0(m.mk_not(eq0), m);
|
||||
add_consequence(neq0);
|
||||
}
|
||||
expr_ref y(seq.str.mk_concat(es, es[0]->get_sort()), m);
|
||||
ctx.add_solution(seq.str.mk_ubv2s(n), y);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Equation is of the form x ++ xs = ys ++ x
|
||||
* where |xs| = |ys| are units of same length
|
||||
|
|
|
@ -64,6 +64,12 @@ namespace seq {
|
|||
bool reduce_itos3(eqr const& e, eq_ptr& r);
|
||||
bool match_itos3(eqr const& e, expr*& n, expr_ref_vector const* & es);
|
||||
|
||||
bool match_ubv2s1(eqr const& e, expr*& s, expr*& t);
|
||||
bool reduce_ubv2s1(eqr const& e, eq_ptr& r);
|
||||
|
||||
bool match_ubv2s2(eqr const& e, expr*& n, expr_ref_vector const*& es);
|
||||
bool reduce_ubv2s2(eqr const& e, eq_ptr& r);
|
||||
|
||||
bool match_binary_eq(eqr const& e, expr_ref& x, ptr_vector<expr>& xs, ptr_vector<expr>& ys, expr_ref& y);
|
||||
bool reduce_binary_eq(eqr const& e, eq_ptr& r);
|
||||
|
||||
|
|
|
@ -714,6 +714,10 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
SASSERT(num_args == 1);
|
||||
st = mk_str_stoi(args[0], result);
|
||||
break;
|
||||
case OP_STRING_UBVTOS:
|
||||
SASSERT(num_args == 1);
|
||||
st = mk_str_ubv2s(args[0], result);
|
||||
break;
|
||||
case _OP_STRING_CONCAT:
|
||||
case _OP_STRING_PREFIX:
|
||||
case _OP_STRING_SUFFIX:
|
||||
|
@ -2204,6 +2208,17 @@ br_status seq_rewriter::mk_str_is_digit(expr* a, expr_ref& result) {
|
|||
}
|
||||
|
||||
|
||||
br_status seq_rewriter::mk_str_ubv2s(expr* a, expr_ref& result) {
|
||||
bv_util bv(m());
|
||||
rational val;
|
||||
if (bv.is_numeral(a, val)) {
|
||||
result = str().mk_string(zstring(val));
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
||||
br_status seq_rewriter::mk_str_itos(expr* a, expr_ref& result) {
|
||||
rational r;
|
||||
if (m_autil.is_numeral(a, r)) {
|
||||
|
@ -2265,6 +2280,11 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
|
|||
result = m().mk_ite(m_autil.mk_ge(b, zero()), b, minus_one());
|
||||
return BR_DONE;
|
||||
}
|
||||
if (str().is_ubv2s(a, b)) {
|
||||
bv_util bv(m());
|
||||
result = bv.mk_bv2int(b);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
if (m().is_ite(a, c, t, e)) {
|
||||
|
|
|
@ -228,6 +228,7 @@ class seq_rewriter {
|
|||
br_status mk_str_units(func_decl* f, expr_ref& result);
|
||||
br_status mk_str_itos(expr* a, expr_ref& result);
|
||||
br_status mk_str_stoi(expr* a, expr_ref& result);
|
||||
br_status mk_str_ubv2s(expr* a, expr_ref& result);
|
||||
br_status mk_str_in_regexp(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_str_to_regexp(expr* a, expr_ref& result);
|
||||
br_status mk_str_le(expr* a, expr* b, expr_ref& result);
|
||||
|
|
|
@ -201,3 +201,6 @@ expr_ref skolem::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned j, e
|
|||
return expr_ref(seq.mk_skolem(m_aut_step, args.size(), args.data(), m.mk_bool_sort()), m);
|
||||
}
|
||||
|
||||
expr_ref skolem::mk_digit2bv(expr* ch, sort* bv_sort) {
|
||||
return mk(symbol("seq.digit2bv"), ch, nullptr, nullptr, nullptr, bv_sort);
|
||||
}
|
||||
|
|
|
@ -93,6 +93,8 @@ namespace seq {
|
|||
expr_ref mk_is_digit(expr* ch) { return mk(symbol("seq.is_digit"), ch, nullptr, nullptr, nullptr, m.mk_bool_sort()); }
|
||||
expr_ref mk_unit_inv(expr* n);
|
||||
expr_ref mk_digit2int(expr* ch) { return mk(symbol("seq.digit2int"), ch, nullptr, nullptr, nullptr, a.mk_int()); }
|
||||
expr_ref mk_digit2bv(expr* ch, sort* bv_sort);
|
||||
expr_ref mk_ubv2ch(expr* b) { return mk(symbol("seq.ubv2ch"), b, nullptr, nullptr, nullptr, seq.mk_char_sort()); }
|
||||
expr_ref mk_left(expr* x, expr* y, expr* z = nullptr) { return mk("seq.left", x, y, z); }
|
||||
expr_ref mk_right(expr* x, expr* y, expr* z = nullptr) { return mk("seq.right", x, y, z); }
|
||||
expr_ref mk_max_unfolding_depth(unsigned d);
|
||||
|
|
|
@ -350,6 +350,17 @@ func_decl* seq_decl_plugin::mk_left_assoc_fun(decl_kind k, unsigned arity, sort*
|
|||
return mk_assoc_fun(k, arity, domain, range, k_seq, k_string, false);
|
||||
}
|
||||
|
||||
func_decl* seq_decl_plugin::mk_ubv2s(unsigned arity, sort* const* domain) {
|
||||
ast_manager& m = *m_manager;
|
||||
if (arity != 1)
|
||||
m.raise_exception("Invalid str.from_ubv expects one bit-vector argument");
|
||||
bv_util bv(m);
|
||||
if (!bv.is_bv_sort(domain[0]))
|
||||
m.raise_exception("Invalid str.from_ubv expects one bit-vector argument");
|
||||
sort* rng = m_string;
|
||||
return m.mk_func_decl(symbol("str.from_ubv"), arity, domain, rng, func_decl_info(m_family_id, OP_STRING_UBVTOS));
|
||||
}
|
||||
|
||||
func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_seq, decl_kind k_string, bool is_right) {
|
||||
ast_manager& m = *m_manager;
|
||||
sort_ref rng(m);
|
||||
|
@ -400,14 +411,14 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
case OP_STRING_STOI:
|
||||
case OP_STRING_LT:
|
||||
case OP_STRING_LE:
|
||||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
|
||||
case OP_STRING_IS_DIGIT:
|
||||
case OP_STRING_TO_CODE:
|
||||
case OP_STRING_FROM_CODE:
|
||||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
|
||||
|
||||
case OP_STRING_UBVTOS:
|
||||
return mk_ubv2s(arity, domain);
|
||||
|
||||
case _OP_REGEXP_FULL_CHAR:
|
||||
m_has_re = true;
|
||||
if (!range) range = mk_reglan();
|
||||
|
@ -615,6 +626,7 @@ void seq_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol cons
|
|||
op_names.push_back(builtin_name("int.to.str", OP_STRING_ITOS));
|
||||
op_names.push_back(builtin_name("re.nostr", _OP_REGEXP_EMPTY));
|
||||
op_names.push_back(builtin_name("re.complement", OP_RE_COMPLEMENT));
|
||||
op_names.push_back(builtin_name("str.from_ubv", OP_STRING_UBVTOS));
|
||||
}
|
||||
|
||||
void seq_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
|
||||
|
|
|
@ -79,6 +79,7 @@ enum seq_op_kind {
|
|||
OP_STRING_CONST,
|
||||
OP_STRING_ITOS,
|
||||
OP_STRING_STOI,
|
||||
OP_STRING_UBVTOS,
|
||||
OP_STRING_LT,
|
||||
OP_STRING_LE,
|
||||
OP_STRING_IS_DIGIT,
|
||||
|
@ -149,6 +150,7 @@ class seq_decl_plugin : public decl_plugin {
|
|||
func_decl* mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string, decl_kind k_seq);
|
||||
func_decl* mk_left_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string, decl_kind k_seq);
|
||||
func_decl* mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string, decl_kind k_seq, bool is_right);
|
||||
func_decl* mk_ubv2s(unsigned arity, sort* const* domain);
|
||||
|
||||
|
||||
void init();
|
||||
|
@ -294,6 +296,7 @@ public:
|
|||
app* mk_char_bit(expr* e, unsigned i);
|
||||
app* mk_itos(expr* i) const { return m.mk_app(m_fid, OP_STRING_ITOS, 1, &i); }
|
||||
app* mk_stoi(expr* s) const { return m.mk_app(m_fid, OP_STRING_STOI, 1, &s); }
|
||||
app* mk_ubv2s(expr* b) const { return m.mk_app(m_fid, OP_STRING_UBVTOS, 1, &b); }
|
||||
app* mk_is_empty(expr* s) const;
|
||||
app* mk_lex_lt(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_STRING_LT, 2, es); }
|
||||
app* mk_lex_le(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_STRING_LE, 2, es); }
|
||||
|
@ -332,6 +335,7 @@ public:
|
|||
bool is_suffix(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_SUFFIX); }
|
||||
bool is_itos(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_ITOS); }
|
||||
bool is_stoi(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_STOI); }
|
||||
bool is_ubv2s(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_UBVTOS); }
|
||||
bool is_in_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_IN_RE); }
|
||||
bool is_unit(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_UNIT); }
|
||||
bool is_lt(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_LT); }
|
||||
|
@ -369,6 +373,7 @@ public:
|
|||
MATCH_BINARY(is_le);
|
||||
MATCH_UNARY(is_itos);
|
||||
MATCH_UNARY(is_stoi);
|
||||
MATCH_UNARY(is_ubv2s);
|
||||
MATCH_UNARY(is_is_digit);
|
||||
MATCH_UNARY(is_from_code);
|
||||
MATCH_UNARY(is_to_code);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue