3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-02 09:20:22 +00:00

Z3str3: add str.to_code and str.from_code (#5015)

This commit is contained in:
Murphy Berzish 2021-02-18 16:51:34 -06:00 committed by GitHub
parent ca9fcbd1df
commit 27db97c269
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 197 additions and 5 deletions

View file

@ -831,6 +831,10 @@ namespace smt {
instantiate_axiom_Replace(e);
} else if (u.str.is_in_re(a)) {
instantiate_axiom_RegexIn(e);
} else if (u.str.is_from_code(a)) {
instantiate_axiom_str_from_code(e);
} else if (u.str.is_to_code(a)) {
instantiate_axiom_str_to_code(e);
} else {
TRACE("str", tout << "BUG: unhandled library-aware term " << mk_pp(e->get_owner(), get_manager()) << std::endl;);
NOT_IMPLEMENTED_YET();
@ -1824,6 +1828,71 @@ namespace smt {
}
}
void theory_str::instantiate_axiom_str_from_code(enode * e) {
ast_manager & m = get_manager();
app * ex = e->get_owner();
if (axiomatized_terms.contains(ex)) {
TRACE("str", tout << "already set up str.from_code axiom for " << mk_pp(ex, m) << std::endl;);
return;
}
axiomatized_terms.insert(ex);
TRACE("str", tout << "instantiate str.from_code axiom for " << mk_pp(ex, m) << std::endl;);
expr * arg;
u.str.is_from_code(ex, arg);
// (str.from_code N) == "" if N is not in the range [0, max_char].
{
expr_ref premise(m.mk_or(m_autil.mk_le(arg, mk_int(-1)), m_autil.mk_ge(arg, mk_int(u.max_char() + 1))), m);
expr_ref conclusion(ctx.mk_eq_atom(ex, mk_string("")), m);
expr_ref axiom(rewrite_implication(premise, conclusion), m);
assert_axiom_rw(axiom);
}
// len (str.from_code N) == 1 if N is in the range [0, max_char].
{
expr_ref premise(m.mk_and(m_autil.mk_ge(arg, mk_int(0)), m_autil.mk_le(arg, mk_int(u.max_char() + 1))), m);
expr_ref conclusion(ctx.mk_eq_atom(mk_strlen(ex), mk_int(1)), m);
expr_ref axiom(rewrite_implication(premise, conclusion), m);
assert_axiom_rw(axiom);
}
// If N is in the range [0, max_char], then to_code(from_code(e)) == e.
{
expr_ref premise(m.mk_and(m_autil.mk_ge(arg, mk_int(0)), m_autil.mk_le(arg, mk_int(u.max_char() + 1))), m);
expr_ref conclusion(ctx.mk_eq_atom(u.str.mk_to_code(ex), arg), m);
expr_ref axiom(rewrite_implication(premise, conclusion), m);
assert_axiom_rw(axiom);
}
}
void theory_str::instantiate_axiom_str_to_code(enode * e) {
ast_manager & m = get_manager();
app * ex = e->get_owner();
if (axiomatized_terms.contains(ex)) {
TRACE("str", tout << "already set up str.to_code axiom for " << mk_pp(ex, m) << std::endl;);
return;
}
axiomatized_terms.insert(ex);
TRACE("str", tout << "instantiate str.to_code axiom for " << mk_pp(ex, m) << std::endl;);
expr * arg;
u.str.is_to_code(ex, arg);
// (str.to_code S) == -1 if len(S) != 1.
{
expr_ref premise(m.mk_not(ctx.mk_eq_atom(mk_strlen(arg), mk_int(1))), m);
expr_ref conclusion(ctx.mk_eq_atom(ex, mk_int(-1)), m);
expr_ref axiom(rewrite_implication(premise, conclusion), m);
assert_axiom_rw(axiom);
}
// (str.to_code S) is in [0, max_char] if len(S) == 1.
{
expr_ref premise(ctx.mk_eq_atom(mk_strlen(arg), mk_int(1)), m);
expr_ref conclusion(m.mk_and(m_autil.mk_ge(ex, mk_int(0)), m_autil.mk_le(ex, mk_int(u.max_char()))), m);
expr_ref axiom(rewrite_implication(premise, conclusion), m);
assert_axiom_rw(axiom);
}
}
expr * theory_str::mk_RegexIn(expr * str, expr * regexp) {
app * regexIn = u.re.mk_in_re(str, regexp);
// immediately force internalization so that axiom setup does not fail
@ -6774,7 +6843,7 @@ namespace smt {
if (ex_sort != str_sort) return false;
// string constants cannot be variables
if (u.str.is_string(e)) return false;
if (u.str.is_concat(e) || u.str.is_at(e) || u.str.is_extract(e) || u.str.is_replace(e) || u.str.is_itos(e))
if (u.str.is_concat(e) || u.str.is_at(e) || u.str.is_extract(e) || u.str.is_replace(e) || u.str.is_itos(e) || u.str.is_from_code(e))
return false;
if (m.is_ite(e))
return false;
@ -6798,8 +6867,7 @@ namespace smt {
sort * int_sort = m.mk_sort(m_arith_fid, INT_SORT);
// reject unhandled expressions
if (u.str.is_replace_all(ex) || u.str.is_replace_re(ex) || u.str.is_replace_re_all(ex) || u.str.is_from_code(ex)
|| u.str.is_to_code(ex) || u.str.is_is_digit(ex)) {
if (u.str.is_replace_all(ex) || u.str.is_replace_re(ex) || u.str.is_replace_re_all(ex) || u.str.is_is_digit(ex)) {
TRACE("str", tout << "ERROR: Z3str3 has encountered an unsupported operator. Aborting." << std::endl;);
m.raise_exception("Z3str3 encountered an unsupported operator.");
}
@ -6830,6 +6898,11 @@ namespace smt {
string_int_conversion_terms.push_back(ap);
m_library_aware_axiom_todo.push_back(n);
m_library_aware_trail_stack.push(push_back_trail<enode*, false>(m_library_aware_axiom_todo));
} else if (u.str.is_from_code(ap)) {
TRACE("str", tout << "found string-codepoint conversion term: " << mk_pp(ex, get_manager()) << std::endl;);
string_int_conversion_terms.push_back(ap);
m_library_aware_axiom_todo.push_back(n);
m_library_aware_trail_stack.push(push_back_trail<enode*, false>(m_library_aware_axiom_todo));
} else if (is_var(ex)) {
// if ex is a variable, add it to our list of variables
TRACE("str", tout << "tracking variable " << mk_ismt2_pp(ap, get_manager()) << std::endl;);
@ -6881,6 +6954,11 @@ namespace smt {
string_int_conversion_terms.push_back(ap);
m_library_aware_axiom_todo.push_back(n);
m_library_aware_trail_stack.push(push_back_trail<enode*, false>(m_library_aware_axiom_todo));
} else if (u.str.is_to_code(ex)) {
TRACE("str", tout << "found string-codepoint conversion term: " << mk_pp(ex, get_manager()) << std::endl;);
string_int_conversion_terms.push_back(ap);
m_library_aware_axiom_todo.push_back(n);
m_library_aware_trail_stack.push(push_back_trail<enode*, false>(m_library_aware_axiom_todo));
}
}
} else {
@ -8617,8 +8695,6 @@ namespace smt {
if (axiomAdd) {
addedStrIntAxioms = true;
}
} else {
UNREACHABLE();
}
}
if (addedStrIntAxioms) {