3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-02 17:30:23 +00:00

Merge branch 'master' of https://github.com/z3prover/z3 into polysat

This commit is contained in:
Nikolaj Bjorner 2021-08-04 14:02:41 -07:00
commit 0249d009f1
109 changed files with 1692 additions and 1097 deletions

View file

@ -248,8 +248,7 @@ public:
}
}
void operator()(quantifier * n) {
display_def_header(n);
void display_quantifier_header(quantifier* n) {
m_out << "(" << (n->get_kind() == forall_k ? "forall" : (n->get_kind() == exists_k ? "exists" : "lambda")) << " ";
unsigned num_decls = n->get_num_decls();
m_out << "(vars ";
@ -272,6 +271,12 @@ public:
display_children(n->get_num_no_patterns(), n->get_no_patterns());
m_out << ") ";
}
}
void operator()(quantifier * n) {
display_def_header(n);
display_quantifier_header(n);
display_child(n->get_expr());
m_out << ")\n";
}
@ -281,6 +286,12 @@ public:
m_out << "(:var " << to_var(n)->get_idx() << ")";
return;
}
if (is_quantifier(n)) {
display_quantifier_header(to_quantifier(n));
display(to_quantifier(n)->get_expr(), depth - 1);
m_out << ")";
return;
}
if (!is_app(n) || depth == 0 || to_app(n)->get_num_args() == 0) {
display_child(n);
@ -304,16 +315,11 @@ public:
void display_bounded(ast * n, unsigned depth) {
if (!n)
m_out << "null";
else if (is_app(n)) {
display(to_expr(n), depth);
}
else if (is_var(n)) {
m_out << "(:var " << to_var(n)->get_idx() << ")";
}
else {
m_out << "#" << n->get_id();
}
m_out << "null";
else if (is_expr(n))
display(to_expr(n), depth);
else
m_out << "#" << n->get_id();
}
};

View file

@ -31,6 +31,7 @@ struct mk_pp : public mk_ismt2_pp {
}
};
//<! print vector of ASTs
class mk_pp_vec {
ast_manager & m;
@ -54,3 +55,16 @@ inline std::ostream& operator<<(std::ostream & out, mk_pp_vec const & pp) {
}
inline std::string operator+(char const* s, mk_pp const& pp) {
std::ostringstream strm;
strm << s << pp;
return strm.str();
}
inline std::string operator+(std::string const& s, mk_pp const& pp) {
std::ostringstream strm;
strm << s << pp;
return strm.str();
}

View file

@ -423,6 +423,7 @@ public:
app * mk_ule(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_ULEQ, arg1, arg2); }
app * mk_sle(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLEQ, arg1, arg2); }
app * mk_slt(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLT, arg1, arg2); }
app * mk_extract(unsigned high, unsigned low, expr * n) {
parameter params[2] = { parameter(high), parameter(low) };
return m_manager.mk_app(get_fid(), OP_EXTRACT, 2, params, 1, &n);

View file

@ -129,7 +129,7 @@ namespace euf {
return n;
}
egraph::egraph(ast_manager& m) : m(m), m_table(m), m_exprs(m) {
egraph::egraph(ast_manager& m) : m(m), m_table(m), m_tmp_app(2), m_exprs(m) {
m_tmp_eq = enode::mk_tmp(m_region, 2);
}
@ -417,6 +417,7 @@ namespace euf {
std::swap(r1, r2);
std::swap(n1, n2);
}
if (j.is_congruence() && (m.is_false(r2->get_expr()) || m.is_true(r2->get_expr())))
add_literal(n1, false);
if (n1->is_equality() && n1->value() == l_false)
@ -594,6 +595,12 @@ namespace euf {
return false;
}
enode* egraph::get_enode_eq_to(func_decl* f, unsigned num_args, enode* const* args) {
m_tmp_app.set_decl(f);
m_tmp_app.set_num_args(num_args);
return find(m_tmp_app.get_app(), num_args, args);
}
/**
\brief generate an explanation for a congruence.
Each pair of children under a congruence have the same roots

View file

@ -156,26 +156,27 @@ namespace euf {
svector<update_record> m_updates;
unsigned_vector m_scopes;
enode_vector m_expr2enode;
enode* m_tmp_eq { nullptr };
enode* m_tmp_node { nullptr };
unsigned m_tmp_node_capacity { 0 };
enode* m_tmp_eq = nullptr;
enode* m_tmp_node = nullptr;
unsigned m_tmp_node_capacity = 0;
tmp_app m_tmp_app;
enode_vector m_nodes;
expr_ref_vector m_exprs;
vector<enode_vector> m_decl2enodes;
enode_vector m_empty_enodes;
unsigned m_num_scopes { 0 };
bool m_inconsistent { false };
enode *m_n1 { nullptr };
enode *m_n2 { nullptr };
unsigned m_num_scopes = 0;
bool m_inconsistent = false;
enode *m_n1 = nullptr;
enode *m_n2 = nullptr;
justification m_justification;
unsigned m_new_lits_qhead { 0 };
unsigned m_new_th_eqs_qhead { 0 };
unsigned m_new_lits_qhead = 0;
unsigned m_new_th_eqs_qhead = 0;
svector<enode_bool_pair> m_new_lits;
svector<th_eq> m_new_th_eqs;
bool_vector m_th_propagates_diseqs;
enode_vector m_todo;
stats m_stats;
bool m_uses_congruence { false };
bool m_uses_congruence = false;
std::function<void(enode*,enode*)> m_on_merge;
std::function<void(enode*)> m_on_make;
std::function<void(expr*,expr*,expr*)> m_used_eq;
@ -261,7 +262,7 @@ namespace euf {
*/
bool are_diseq(enode* a, enode* b) const;
enode * get_enode_eq_to(func_decl * f, unsigned num_args, enode * const * args) { UNREACHABLE(); return nullptr; }
enode* get_enode_eq_to(func_decl* f, unsigned num_args, enode* const* args);
/**
\brief Maintain and update cursor into propagated consequences.
@ -326,6 +327,7 @@ namespace euf {
void collect_statistics(statistics& st) const;
unsigned num_scopes() const { return m_scopes.size() + m_num_scopes; }
unsigned num_nodes() const { return m_nodes.size(); }
};
inline std::ostream& operator<<(std::ostream& out, egraph const& g) { return g.display(out); }

View file

@ -125,7 +125,7 @@ namespace euf {
ast_manager & m_manager;
bool m_commutativity{ false }; //!< true if the last found congruence used commutativity
bool m_commutativity = false; //!< true if the last found congruence used commutativity
ptr_vector<void> m_tables;
map<decl_info, unsigned, decl_hash, decl_eq> m_func_decl2id;

View file

@ -467,7 +467,7 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decl
See normalize_expr
*/
void macro_util::mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const {
TRACE("macro_util", tout << mk_pp(head, m_manager) << "\n";);
TRACE("macro_util", tout << mk_pp(head, m_manager) << "\n" << mk_pp(def, m_manager) << "\n";);
SASSERT(is_macro_head(head, head->get_num_args()) ||
is_quasi_macro_ok(head, head->get_num_args(), def));
SASSERT(!occurs(head->get_decl(), def));

View file

@ -110,10 +110,9 @@ bool quasi_macros::fully_depends_on(app * a, quantifier * q) const {
// direct argument of a, i.e., a->get_arg(i) == v for some i
bit_vector bitset;
bitset.resize(q->get_num_decls(), false);
for (unsigned i = 0 ; i < a->get_num_args() ; i++) {
if (is_var(a->get_arg(i)))
bitset.set(to_var(a->get_arg(i))->get_idx(), true);
}
for (expr* arg : *a)
if (is_var(arg))
bitset.set(to_var(arg)->get_idx(), true);
for (unsigned i = 0; i < bitset.size() ; i++) {
if (!bitset.get(i))
@ -198,6 +197,7 @@ bool quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant
bit_vector v_seen;
v_seen.resize(q->get_num_decls(), false);
unsigned num_seen = 0;
for (unsigned i = 0; i < a->get_num_args(); ++i) {
expr* arg = a->get_arg(i);
if (!is_var(arg) && !is_ground(arg))
@ -215,8 +215,11 @@ bool quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant
var * v = to_var(arg);
m_new_vars.push_back(v);
v_seen.set(v->get_idx(), true);
++num_seen;
}
}
if (num_seen < q->get_num_decls())
return false;
// Reverse the new variable names and sorts. [CMW: There is a smarter way to do this.]
vector<symbol> new_var_names_rev;

View file

@ -281,9 +281,9 @@ struct pull_quant::imp {
m.mk_rewrite(old_q, result);
return true;
}
if (is_lambda(old_q)) {
return false;
}
if (is_lambda(old_q))
return false;
if (!is_forall(new_body))
return false;

View file

@ -209,6 +209,7 @@ namespace recfun {
void def::compute_cases(util& u,
replace& subst,
is_immediate_pred & is_i,
bool is_macro,
unsigned n_vars, var *const * vars, expr* rhs)
{
VERIFY(m_cases.empty() && "cases cannot already be computed");
@ -227,7 +228,7 @@ namespace recfun {
expr_ref_vector conditions(m);
// is the function a macro (unconditional body)?
if (n_vars == 0 || !contains_ite(u, rhs)) {
if (is_macro || n_vars == 0 || !contains_ite(u, rhs)) {
// constant function or trivial control flow, only one (dummy) case
add_case(name, 0, conditions, rhs);
return;
@ -335,10 +336,11 @@ namespace recfun {
return alloc(def, m(), m_fid, name, n, domain, range, is_generated);
}
void util::set_definition(replace& subst, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) {
expr_ref rhs1 = get_plugin().redirect_ite(subst, n_vars, vars, rhs);
d.set_definition(subst, n_vars, vars, rhs1);
void util::set_definition(replace& subst, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) {
expr_ref rhs1(rhs, m());
if (!is_macro)
rhs1 = get_plugin().redirect_ite(subst, n_vars, vars, rhs);
d.set_definition(subst, is_macro, n_vars, vars, rhs1);
}
app_ref util::mk_num_rounds_pred(unsigned d) {
@ -369,11 +371,11 @@ namespace recfun {
};
// set definition
void promise_def::set_definition(replace& r, unsigned n_vars, var * const * vars, expr * rhs) {
void promise_def::set_definition(replace& r, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) {
SASSERT(n_vars == d->get_arity());
is_imm_pred is_i(*u);
d->compute_cases(*u, r, is_i, n_vars, vars, rhs);
d->compute_cases(*u, r, is_i, is_macro, n_vars, vars, rhs);
}
namespace decl {
@ -426,8 +428,8 @@ namespace recfun {
}
}
void plugin::set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) {
u().set_definition(r, d, n_vars, vars, rhs);
void plugin::set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) {
u().set_definition(r, d, is_macro, n_vars, vars, rhs);
for (case_def & c : d.get_def()->get_cases()) {
m_case_defs.insert(c.get_decl(), &c);
}
@ -437,12 +439,12 @@ namespace recfun {
return !m_case_defs.empty();
}
def* plugin::mk_def(replace& subst,
def* plugin::mk_def(replace& subst, bool is_macro,
symbol const& name, unsigned n, sort ** params, sort * range,
unsigned n_vars, var ** vars, expr * rhs) {
promise_def d = mk_def(name, n, params, range);
SASSERT(! m_defs.contains(d.get_def()->get_decl()));
set_definition(subst, d, n_vars, vars, rhs);
set_definition(subst, d, is_macro, n_vars, vars, rhs);
return d.get_def();
}
@ -520,7 +522,7 @@ namespace recfun {
auto pd = mk_def(fresh_name, n, domain.data(), max_expr->get_sort());
func_decl* f = pd.get_def()->get_decl();
expr_ref new_body(m().mk_app(f, n, args.data()), m());
set_definition(subst, pd, n, vars, max_expr);
set_definition(subst, pd, false, n, vars, max_expr);
subst.reset();
subst.insert(max_expr, new_body);
result = subst(result);
@ -528,7 +530,6 @@ namespace recfun {
}
return result;
}
}
case_expansion::case_expansion(recfun::util& u, app * n) :

View file

@ -114,7 +114,7 @@ namespace recfun {
// compute cases for a function, given its RHS (possibly containing `ite`).
void compute_cases(util& u, replace& subst, is_immediate_pred &,
unsigned n_vars, var *const * vars, expr* rhs);
bool is_macro, unsigned n_vars, var *const * vars, expr* rhs);
void add_case(std::string & name, unsigned case_index, expr_ref_vector const& conditions, expr* rhs, bool is_imm = false);
bool contains_ite(util& u, expr* e); // expression contains a test over a def?
bool contains_def(util& u, expr* e); // expression contains a def
@ -138,7 +138,7 @@ namespace recfun {
friend class util;
util * u;
def * d;
void set_definition(replace& r, unsigned n_vars, var * const * vars, expr * rhs); // call only once
void set_definition(replace& r, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs); // call only once
public:
promise_def(util * u, def * d) : u(u), d(d) {}
promise_def(promise_def const & from) : u(from.u), d(from.d) {}
@ -182,9 +182,9 @@ namespace recfun {
promise_def ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated = false);
void set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs);
void set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs);
def* mk_def(replace& subst, symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs);
def* mk_def(replace& subst, bool is_macro, symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs);
void erase_def(func_decl* f);
@ -216,7 +216,7 @@ namespace recfun {
decl::plugin * m_plugin;
bool compute_is_immediate(expr * rhs);
void set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs);
void set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs);
public:
util(ast_manager &m);

View file

@ -776,48 +776,84 @@ namespace seq {
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);
}
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;
rational p(1);
for (unsigned i = 0; i <= k; ++i) {
if (pow > 1)
bb = bv.mk_bv_udiv(b, bv.mk_numeral(pow, bv_sort));
if (p > 1)
bb = bv.mk_bv_udiv(b, bv.mk_numeral(p, bv_sort));
es.push_back(seq.str.mk_unit(m_sk.mk_ubv2ch(bv.mk_bv_urem(bb, ten))));
pow *= 10;
p *= 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);
SASSERT(pow < rational::power_of_two(sz));
if (k == 0)
add_clause(ge10k1, eq);
else if (pow * 10 >= rational::power_of_two(sz))
add_clause(~ge10k, eq);
else
add_clause(~ge10k, ge10k1, eq);
}
/*
* 1 <= len(ubv2s(b)) <= k, where k is min such that 10^k > 2^sz
*/
void axioms::ubv2s_len_axiom(expr* b) {
bv_util bv(m);
sort* bv_sort = b->get_sort();
unsigned sz = bv.get_bv_size(bv_sort);
unsigned k = 1;
rational pow(10);
while (pow <= rational::power_of_two(sz))
++k, pow *= 10;
expr_ref len(seq.str.mk_length(seq.str.mk_ubv2s(b)), m);
expr_ref ge(a.mk_ge(len, a.mk_int(1)), m);
expr_ref le(a.mk_le(len, a.mk_int(k)), m);
add_clause(le);
add_clause(ge);
}
/*
* len(ubv2s(b)) = k => 10^k-1 <= b < 10^{k} k > 1
* len(ubv2s(b)) = 1 => b < 10^{1} k = 1
* len(ubv2s(b)) >= k => is_digit(nth(ubv2s(b), 0)) & ... & is_digit(nth(ubv2s(b), k-1))
*/
void axioms::ubv2s_len_axiom(expr* b, unsigned k) {
expr_ref ge10k(m), ge10k1(m), eq(m);
expr_ref ge10k(m), ge10k1(m), eq(m), is_digit(m);
expr_ref ubvs(seq.str.mk_ubv2s(b), m);
expr_ref len(seq.str.mk_length(ubvs), m);
expr_ref ge_len(a.mk_ge(len, a.mk_int(k)), 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
if (pow >= rational::power_of_two(sz)) {
expr_ref ge(a.mk_ge(len, a.mk_int(k)), m);
add_clause(~ge);
return;
}
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);
eq = m.mk_eq(len, a.mk_int(k));
if (pow * 10 < rational::power_of_two(sz))
add_clause(~eq, ~ge10k1);
if (k > 1)
add_clause(~eq, ge10k);
for (unsigned i = 0; i < k; ++i) {
expr* ch = seq.str.mk_nth_i(ubvs, i);
is_digit = seq.mk_char_is_digit(ch);
add_clause(~ge_len, is_digit);
}
}
void axioms::ubv2ch_axiom(sort* bv_sort) {

View file

@ -96,6 +96,7 @@ namespace seq {
void itos_axiom(expr* s, unsigned k);
void ubv2s_axiom(expr* b, unsigned k);
void ubv2s_len_axiom(expr* b, unsigned k);
void ubv2s_len_axiom(expr* b);
void ubv2ch_axiom(sort* bv_sort);
void lt_axiom(expr* n);
void le_axiom(expr* n);

View file

@ -672,6 +672,14 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
SASSERT(num_args == 3);
st = mk_seq_replace_all(args[0], args[1], args[2], result);
break;
case OP_SEQ_REPLACE_RE:
SASSERT(num_args == 3);
st = mk_seq_replace_re(args[0], args[1], args[2], result);
break;
case OP_SEQ_REPLACE_RE_ALL:
SASSERT(num_args == 3);
st = mk_seq_replace_re_all(args[0], args[1], args[2], result);
break;
case OP_SEQ_TO_RE:
SASSERT(num_args == 1);
st = mk_str_to_regexp(args[0], result);
@ -718,6 +726,10 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
SASSERT(num_args == 1);
st = mk_str_ubv2s(args[0], result);
break;
case OP_STRING_SBVTOS:
SASSERT(num_args == 1);
st = mk_str_sbv2s(args[0], result);
break;
case _OP_STRING_CONCAT:
case _OP_STRING_PREFIX:
case _OP_STRING_SUFFIX:
@ -1900,6 +1912,8 @@ br_status seq_rewriter::mk_seq_replace_all(expr* a, expr* b, expr* c, expr_ref&
result = str().mk_concat(strs, a->get_sort());
return BR_REWRITE_FULL;
}
// TBD: add case when a, b are concatenation of units that are values.
// in this case we can use a similar loop as for strings.
return BR_FAILED;
}
@ -1911,7 +1925,6 @@ br_status seq_rewriter::mk_seq_replace_re(expr* a, expr* b, expr* c, expr_ref& r
return BR_FAILED;
}
br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
TRACE("seq", tout << mk_pp(a, m()) << " " << mk_pp(b, m()) << "\n";);
zstring s1, s2;
@ -2218,6 +2231,30 @@ br_status seq_rewriter::mk_str_ubv2s(expr* a, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_str_sbv2s(expr *a, expr_ref &result) {
bv_util bv(m());
rational val;
unsigned bv_size = 0;
if (bv.is_numeral(a, val, bv_size)) {
rational r = mod(val, rational::power_of_two(bv_size));
SASSERT(!r.is_neg());
if (r >= rational::power_of_two(bv_size - 1)) {
r -= rational::power_of_two(bv_size);
}
result = str().mk_string(zstring(r));
return BR_DONE;
}
bv_size = bv.get_bv_size(a);
result = m().mk_ite(
bv.mk_slt(a,bv.mk_numeral(0, bv_size)),
str().mk_concat(
str().mk_string(zstring("-")),
str().mk_ubv2s(bv.mk_bv_neg(a))
),
str().mk_ubv2s(a));
return BR_REWRITE_FULL;
}
br_status seq_rewriter::mk_str_itos(expr* a, expr_ref& result) {
rational r;
@ -3158,7 +3195,7 @@ expr_ref seq_rewriter::mk_der_cond(expr* cond, expr* ele, sort* seq_sort) {
expr *c1 = nullptr, *c2 = nullptr, *ch1 = nullptr, *ch2 = nullptr;
unsigned ch = 0;
expr_ref result(m()), r1(m()), r2(m());
if (m().is_eq(cond, ch1, ch2)) {
if (m().is_eq(cond, ch1, ch2) && u().is_char(ch1)) {
r1 = u().mk_le(ch1, ch2);
r1 = mk_der_cond(r1, ele, seq_sort);
r2 = u().mk_le(ch2, ch1);
@ -3219,11 +3256,17 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
}
expr_ref dr2 = mk_derivative(ele, r2);
is_n = re_predicate(is_n, seq_sort);
// Instead of mk_der_union here, we use mk_der_antimorov_union to
// force the two cases to be considered separately and lifted to
// the top level. This avoids blowup in cases where determinization
// is expensive.
return mk_der_antimorov_union(result, mk_der_concat(is_n, dr2));
if (re().is_empty(dr2)) {
//do not concatenate [], it is a deade-end
return result;
}
else {
// Instead of mk_der_union here, we use mk_der_antimorov_union to
// force the two cases to be considered separately and lifted to
// the top level. This avoids blowup in cases where determinization
// is expensive.
return mk_der_antimorov_union(result, mk_der_concat(is_n, dr2));
}
}
else if (re().is_star(r, r1)) {
return mk_der_concat(mk_derivative(ele, r1), r);
@ -3256,8 +3299,15 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
if (lo > 0) {
lo--;
}
result = re().mk_loop(r1, lo);
return mk_der_concat(mk_derivative(ele, r1), result);
result = mk_derivative(ele, r1);
//do not concatenate with [] (emptyset)
if (re().is_empty(result)) {
return result;
}
else {
//do not create loop r1{0,}, instead create r1*
return mk_der_concat(result, (lo == 0 ? re().mk_star(r1) : re().mk_loop(r1, lo)));
}
}
else if (re().is_loop(r, r1, lo, hi)) {
if (hi == 0) {
@ -3267,8 +3317,14 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
if (lo > 0) {
lo--;
}
result = re().mk_loop(r1, lo, hi);
return mk_der_concat(mk_derivative(ele, r1), result);
result = mk_derivative(ele, r1);
//do not concatenate with [] (emptyset) or handle the rest of the loop if no more iterations remain
if (re().is_empty(result) || hi == 0) {
return result;
}
else {
return mk_der_concat(result, re().mk_loop(r1, lo, hi));
}
}
else if (re().is_full_seq(r) ||
re().is_empty(r)) {
@ -3288,20 +3344,23 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
return result;
}
else if (str().is_empty(r1)) {
//observe: str().is_empty(r1) checks that r = () = epsilon
//while mk_empty() = [], because deriv(epsilon) = [] = nothing
return mk_empty();
}
#if 0
else {
else if (str().is_itos(r1, r2)) {
//
// here r1 = (str.from_int r2) and r2 is non-ground
// or else the expression would have been simplified earlier
// so r1 must be nonempty and must consists of decimal digits
// '0' <= elem <= '9'
// if ((isdigit ele) and (ele = (hd r1))) then (to_re (tl r1)) else []
//
hd = str().mk_nth_i(r1, m_autil.mk_int(0));
tl = str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1)));
result = re().mk_to_re(tl);
result =
m().mk_ite(m_br.mk_eq_rw(r1, str().mk_empty(m().get_sort(r1))),
mk_empty(),
re_and(m_br.mk_eq_rw(ele, hd), result));
return result;
m_br.mk_and(u().mk_le(m_util.mk_char('0'), ele), u().mk_le(ele, m_util.mk_char('9')), m().mk_eq(hd, ele), result);
tl = re().mk_to_re(str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1))));
return re_and(result, tl);
}
#endif
}
else if (re().is_reverse(r, r1) && re().is_to_re(r1, r2)) {
// Reverses are rewritten so that the only derivative case is
@ -3342,6 +3401,7 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
}
expr* e1 = nullptr, *e2 = nullptr;
if (str().is_unit(r1, e1) && str().is_unit(r2, e2)) {
SASSERT(u().is_char(e1));
// Use mk_der_cond to normalize
STRACE("seq_verbose", tout << "deriv range str" << std::endl;);
expr_ref p1(u().mk_le(e1, ele), m());
@ -3900,6 +3960,7 @@ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
comp(none) -> all
comp(all) -> none
comp(comp(e1)) -> e1
comp(epsilon) -> .+
*/
br_status seq_rewriter::mk_re_complement(expr* a, expr_ref& result) {
expr *e1 = nullptr, *e2 = nullptr;
@ -3923,6 +3984,10 @@ br_status seq_rewriter::mk_re_complement(expr* a, expr_ref& result) {
result = e1;
return BR_DONE;
}
if (re().is_to_re(a, e1) && str().is_empty(e1)) {
result = re().mk_plus(re().mk_full_char(a->get_sort()));
return BR_DONE;
}
return BR_FAILED;
}
@ -4110,6 +4175,7 @@ br_status seq_rewriter::mk_re_power(func_decl* f, expr* a, expr_ref& result) {
a+* = a*
emp* = ""
all* = all
.+* = all
*/
br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
expr* b, *c, *b1, *c1;
@ -4132,7 +4198,10 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
return BR_DONE;
}
if (re().is_plus(a, b)) {
result = re().mk_star(b);
if (re().is_full_char(b))
result = re().mk_full_seq(a->get_sort());
else
result = re().mk_star(b);
return BR_DONE;
}
if (re().is_union(a, b, c)) {

View file

@ -229,6 +229,7 @@ class seq_rewriter {
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_sbv2s(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);

View file

@ -350,7 +350,7 @@ 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) {
func_decl* seq_decl_plugin::mk_ubv2s(unsigned arity, sort* const* domain) const {
ast_manager& m = *m_manager;
if (arity != 1)
m.raise_exception("Invalid str.from_ubv expects one bit-vector argument");
@ -361,6 +361,17 @@ func_decl* seq_decl_plugin::mk_ubv2s(unsigned arity, sort* const* domain) {
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_sbv2s(unsigned arity, sort* const* domain) const {
ast_manager &m = *m_manager;
if (arity != 1)
m.raise_exception("Invalid str.from_sbv expects one bit-vector argument");
bv_util bv(m);
if (!bv.is_bv_sort(domain[0]))
m.raise_exception("Invalid str.from_sbv expects one bit-vector argument");
sort *rng = m_string;
return m.mk_func_decl(symbol("str.from_sbv"), arity, domain, rng, func_decl_info(m_family_id, OP_STRING_SBVTOS));
}
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);
@ -376,7 +387,7 @@ func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* cons
}
func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
func_decl* seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
init();
m_has_seq = true;
@ -416,8 +427,12 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
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);
return mk_ubv2s(arity, domain);
case OP_STRING_SBVTOS:
return mk_sbv2s(arity, domain);
case _OP_REGEXP_FULL_CHAR:
m_has_re = true;
@ -627,6 +642,7 @@ void seq_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol cons
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));
op_names.push_back(builtin_name("str.from_sbv", OP_STRING_SBVTOS));
}
void seq_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {

View file

@ -80,6 +80,7 @@ enum seq_op_kind {
OP_STRING_ITOS,
OP_STRING_STOI,
OP_STRING_UBVTOS,
OP_STRING_SBVTOS,
OP_STRING_LT,
OP_STRING_LE,
OP_STRING_IS_DIGIT,
@ -150,7 +151,8 @@ 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);
func_decl* mk_ubv2s(unsigned arity, sort* const* domain) const;
func_decl* mk_sbv2s(unsigned arity, sort* const* domain) const;
void init();
@ -297,6 +299,7 @@ public:
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_sbv2s(expr* b) const { return m.mk_app(m_fid, OP_STRING_SBVTOS, 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); }
@ -336,6 +339,7 @@ public:
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_sbv2s(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_SBVTOS); }
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); }
@ -374,6 +378,7 @@ public:
MATCH_UNARY(is_itos);
MATCH_UNARY(is_stoi);
MATCH_UNARY(is_ubv2s);
MATCH_UNARY(is_sbv2s);
MATCH_UNARY(is_is_digit);
MATCH_UNARY(is_from_code);
MATCH_UNARY(is_to_code);