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:
commit
0249d009f1
109 changed files with 1692 additions and 1097 deletions
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue