mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
str.from_ubv step2
This commit is contained in:
parent
1bc10cebc5
commit
b6a3891ac4
10 changed files with 230 additions and 2 deletions
|
@ -769,6 +769,43 @@ 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);
|
||||
expr_ref_vector es(m);
|
||||
expr_ref bb(b, m);
|
||||
unsigned sz = bv.get_bv_size(b);
|
||||
for (unsigned i = 0; i < k; ++i) {
|
||||
es.push_back(seq.str.mk_unit(m_sk.mk_ubv2ch(bv.mk_bv_urem(bb, bv.mk_numeral(10, sz)))));
|
||||
}
|
||||
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);
|
||||
ubv2ch_axiom(bv_sort);
|
||||
|
||||
}
|
||||
|
||||
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,8 @@ 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 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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -296,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); }
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace smt {
|
|||
void add_stoi_axiom(expr* n) { m_ax.stoi_axiom(n); }
|
||||
void add_stoi_axiom(expr* e, unsigned k) { m_ax.stoi_axiom(e, k); }
|
||||
void add_itos_axiom(expr* s, unsigned k) { m_ax.itos_axiom(s, k); }
|
||||
void add_ubv2s_axiom(expr* b, unsigned k) { m_ax.ubv2s_axiom(b, k); }
|
||||
void add_lt_axiom(expr* n) { m_ax.lt_axiom(n); }
|
||||
void add_le_axiom(expr* n) { m_ax.le_axiom(n); }
|
||||
void add_is_digit_axiom(expr* n) { m_ax.is_digit_axiom(n); }
|
||||
|
|
|
@ -262,6 +262,7 @@ theory_seq::theory_seq(context& ctx):
|
|||
m_axioms(m),
|
||||
m_axioms_head(0),
|
||||
m_int_string(m),
|
||||
m_ubv_string(m),
|
||||
m_length(m),
|
||||
m_length_limit(m),
|
||||
m_mg(nullptr),
|
||||
|
@ -368,6 +369,11 @@ final_check_status theory_seq::final_check_eh() {
|
|||
TRACEFIN("int_string");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (check_ubv_string()) {
|
||||
++m_stats.m_ubv_string;
|
||||
TRACEFIN("ubv_string");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (reduce_length_eq()) {
|
||||
++m_stats.m_branch_variable;
|
||||
TRACEFIN("reduce_length");
|
||||
|
@ -1525,6 +1531,60 @@ bool theory_seq::add_length_to_eqc(expr* e) {
|
|||
return change;
|
||||
}
|
||||
|
||||
void theory_seq::add_ubv_string(expr* e) {
|
||||
m_ubv_string.push_back(e);
|
||||
m_trail_stack.push(push_back_vector<expr_ref_vector>(m_ubv_string));
|
||||
}
|
||||
|
||||
bool theory_seq::check_ubv_string() {
|
||||
bool change = false;
|
||||
for (expr* e : m_ubv_string) {
|
||||
if (check_ubv_string(e))
|
||||
change = true;
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
bool theory_seq::check_ubv_string(expr* e) {
|
||||
expr* n = nullptr;
|
||||
if (ctx.inconsistent())
|
||||
return true;
|
||||
if (m_has_ubv_axiom.contains(e))
|
||||
return false;
|
||||
expr* b = nullptr;
|
||||
bv_util bv(m);
|
||||
VERIFY(m_util.str.is_ubv2s(e, b));
|
||||
unsigned sz = bv.get_bv_size(b);
|
||||
rational value(0);
|
||||
bool all_bits_assigned = true;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr_ref bit(bv.mk_bit2bool(b, i), m);
|
||||
literal lit = mk_literal(bit);
|
||||
switch (ctx.get_assignment(lit)) {
|
||||
case l_undef:
|
||||
ctx.mark_as_relevant(lit);
|
||||
all_bits_assigned = false;
|
||||
break;
|
||||
case l_true:
|
||||
value += rational::power_of_two(i);
|
||||
break;
|
||||
case l_false:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!all_bits_assigned)
|
||||
return true;
|
||||
unsigned k = 0;
|
||||
while (value >= 10) {
|
||||
k++;
|
||||
value = div(value, rational(10));
|
||||
}
|
||||
m_has_ubv_axiom.insert(e);
|
||||
m_trail_stack.push(insert_obj_trail<expr>(m_has_ubv_axiom, e));
|
||||
m_ax.add_ubv2s_axiom(b, k);
|
||||
return true;
|
||||
}
|
||||
|
||||
void theory_seq::add_int_string(expr* e) {
|
||||
m_int_string.push_back(e);
|
||||
m_trail_stack.push(push_back_vector<expr_ref_vector>(m_int_string));
|
||||
|
@ -1761,6 +1821,7 @@ void theory_seq::collect_statistics(::statistics & st) const {
|
|||
st.update("seq extensionality", m_stats.m_extensionality);
|
||||
st.update("seq fixed length", m_stats.m_fixed_length);
|
||||
st.update("seq int.to.str", m_stats.m_int_string);
|
||||
st.update("seq str.from_ubv", m_stats.m_ubv_string);
|
||||
}
|
||||
|
||||
void theory_seq::init_search_eh() {
|
||||
|
@ -3099,6 +3160,9 @@ void theory_seq::relevant_eh(app* n) {
|
|||
add_int_string(n);
|
||||
}
|
||||
|
||||
if (m_util.str.is_ubv2s(n))
|
||||
add_ubv_string(n);
|
||||
|
||||
expr* arg = nullptr;
|
||||
if (m_sk.is_tail(n, arg)) {
|
||||
add_length_limit(arg, m_max_unfolding_depth, true);
|
||||
|
|
|
@ -323,6 +323,7 @@ namespace smt {
|
|||
unsigned m_fixed_length;
|
||||
unsigned m_propagate_contains;
|
||||
unsigned m_int_string;
|
||||
unsigned m_ubv_string;
|
||||
};
|
||||
typedef hashtable<rational, rational::hash_proc, rational::eq_proc> rational_set;
|
||||
|
||||
|
@ -348,6 +349,8 @@ namespace smt {
|
|||
unsigned m_axioms_head; // index of first axiom to add.
|
||||
bool m_incomplete; // is the solver (clearly) incomplete for the fragment.
|
||||
expr_ref_vector m_int_string;
|
||||
expr_ref_vector m_ubv_string; // list all occurrences of str.from_ubv that have been seen
|
||||
obj_hashtable<expr> m_has_ubv_axiom; // keep track of ubv that have been axiomatized within scope.
|
||||
obj_hashtable<expr> m_has_length; // is length applied
|
||||
expr_ref_vector m_length; // length applications themselves
|
||||
obj_map<expr, unsigned> m_length_limit_map; // sequences that have length limit predicates
|
||||
|
@ -569,6 +572,11 @@ namespace smt {
|
|||
bool branch_itos();
|
||||
bool branch_itos(expr* e);
|
||||
|
||||
// functions that convert ubv to string
|
||||
void add_ubv_string(expr* e);
|
||||
bool check_ubv_string();
|
||||
bool check_ubv_string(expr* e);
|
||||
|
||||
expr_ref add_elim_string_axiom(expr* n);
|
||||
void add_in_re_axiom(expr* n);
|
||||
literal mk_simplified_literal(expr* n);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue