3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-16 13:58:45 +00:00

length estimation

This commit is contained in:
Murphy Berzish 2017-12-06 18:32:11 -05:00
parent fbe8d1577e
commit a5c828f6f2
2 changed files with 121 additions and 2 deletions

View file

@ -25,6 +25,8 @@
#include "smt/theory_seq_empty.h"
#include "smt/theory_arith.h"
#include "ast/ast_util.h"
#include "seq_rewriter.h"
#include "smt_kernel.h"
namespace smt {
@ -48,6 +50,7 @@ namespace smt {
finalCheckProgressIndicator(false),
m_trail(m),
m_factory(nullptr),
m_mk_aut(m),
m_unused_id(0),
m_delayed_axiom_setup_terms(m),
tmpStringVarCount(0),
@ -95,6 +98,26 @@ namespace smt {
return u.str.mk_string(sym);
}
class seq_expr_solver : public expr_solver {
kernel m_kernel;
public:
seq_expr_solver(ast_manager& m, smt_params& fp):
m_kernel(m, fp) {}
virtual lbool check_sat(expr* e) {
m_kernel.push();
m_kernel.assert_expr(e);
lbool r = m_kernel.check();
m_kernel.pop(1);
return r;
}
};
void theory_str::init(context * ctx) {
theory::init(ctx);
m_mk_aut.set_solver(alloc(seq_expr_solver, get_manager(),
get_context().get_fparams()));
}
void theory_str::initialize_charset() {
bool defaultCharset = true;
if (defaultCharset) {
@ -1718,6 +1741,11 @@ namespace smt {
regex_in_var_reg_str_map[ex->get_arg(0)].insert(regexStr);
}
if (m_params.m_RegexAutomata) {
// stop setting up axioms here, we do this differently
return;
}
expr_ref str(ex->get_arg(0), m);
app * regex = to_app(ex->get_arg(1));
@ -1887,7 +1915,7 @@ namespace smt {
check_contain_in_new_eq(lhs, rhs);
}
if (!regex_in_bool_map.empty()) {
if (!regex_in_bool_map.empty() && !m_params.m_RegexAutomata) {
TRACE("str", tout << "checking regex consistency" << std::endl;);
check_regex_in(lhs, rhs);
}
@ -6550,6 +6578,92 @@ namespace smt {
return 1;
}
}
/*
* Infer all length constraints implied by the given regular expression `re`
* in order to constrain `lenVar` (which must be of sort Int).
* This assumes that `re` appears in a positive context.
* Returns a Boolean formula expressing the appropriate constraints over `lenVar`.
* In some cases, the returned formula requires one or more free integer variables to be created.
* These variables are returned in the reference parameter `freeVariables`.
* Extra assertions should be made for these free variables constraining them to be non-negative.
*/
expr_ref theory_str::infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables) {
ENSURE(u.is_re(re));
context & ctx = get_context();
ast_manager & m = get_manager();
expr * sub1;
expr * sub2;
if (u.re.is_to_re(re, sub1)) {
SASSERT(u.str.is_string(sub1));
zstring str;
u.str.is_string(sub1, str);
rational strlen(str.length());
expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(strlen, true)), m);
return retval;
} else if (u.re.is_union(re, sub1, sub2)) {
expr_ref r1 = infer_all_regex_lengths(lenVar, sub1, freeVariables);
expr_ref r2 = infer_all_regex_lengths(lenVar, sub2, freeVariables);
expr_ref retval(m.mk_or(r1, r2), m);
return retval;
} else if (u.re.is_concat(re, sub1, sub2)) {
expr * v1 = mk_int_var("rlen1");
expr * v2 = mk_int_var("rlen2");
freeVariables.push_back(v1);
freeVariables.push_back(v2);
expr_ref r1 = infer_all_regex_lengths(v1, sub1, freeVariables);
expr_ref r2 = infer_all_regex_lengths(v2, sub2, freeVariables);
expr_ref_vector finalResult(m);
finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_add(v1, v2)));
finalResult.push_back(r1);
finalResult.push_back(r2);
expr_ref retval(mk_and(finalResult), m);
return retval;
} else if (u.re.is_star(re, sub1)) {
expr * v = mk_int_var("rlen");
expr * n = mk_int_var("rstar");
freeVariables.push_back(v);
freeVariables.push_back(n);
expr_ref rsub = infer_all_regex_lengths(v, sub1, freeVariables);
expr_ref_vector finalResult(m);
finalResult.push_back(rsub);
finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_mul(v, n)));
expr_ref retval(mk_and(finalResult), m);
return retval;
} else if (u.re.is_plus(re, sub1)) {
expr * v = mk_int_var("rlen");
expr * n = mk_int_var("rstar");
freeVariables.push_back(v);
freeVariables.push_back(n);
expr_ref rsub = infer_all_regex_lengths(v, sub1, freeVariables);
expr_ref_vector finalResult(m);
finalResult.push_back(rsub);
finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_mul(v, n)));
finalResult.push_back(m_autil.mk_ge(n, m_autil.mk_numeral(rational::one(), true)));
expr_ref retval(mk_and(finalResult), m);
return retval;
} else if (u.re.is_range(re, sub1, sub2)) {
SASSERT(u.str.is_string(sub1));
SASSERT(u.str.is_string(sub2));
zstring str1, str2;
u.str.is_string(sub1, str1);
u.str.is_string(sub2, str2);
SASSERT(str1.length() == 1);
SASSERT(str2.length() == 1);
expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(rational::one(), true)), m);
return retval;
} else if (u.re.is_full(re)) {
expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(rational::one(), true)), m);
return retval;
} else if (u.re.is_complement(re)) {
// skip complement for now, in general this is difficult to predict
expr_ref retval(m_autil.mk_ge(lenVar, m_autil.mk_numeral(rational::zero(), true)), m);
return retval;
} else {
TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, m) << std::endl;);
expr_ref retval(m_autil.mk_ge(lenVar, m_autil.mk_numeral(rational::zero(), true)), m);
return retval;
}
}
/*
* strArgmt::solve_concat_eq_str()

View file

@ -23,6 +23,7 @@
#include "ast/ast_pp.h"
#include "ast/arith_decl_plugin.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/seq_rewriter.h"
#include "ast/seq_decl_plugin.h"
#include "smt/smt_theory.h"
#include "smt/params/theory_str_params.h"
@ -267,6 +268,8 @@ protected:
str_value_factory * m_factory;
re2automaton m_mk_aut;
// Unique identifier appended to unused variables to ensure that model construction
// does not introduce equalities when they weren't enforced.
unsigned m_unused_id;
@ -461,9 +464,10 @@ protected:
void unroll_str2reg_constStr(expr * unrollFunc, expr * eqConstStr);
void process_concat_eq_unroll(expr * concat, expr * unroll);
// regex automata
// regex automata and length-aware regex
unsigned estimate_regex_complexity(expr * re);
unsigned estimate_regex_complexity_under_complement(expr * re);
expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables);
void set_up_axioms(expr * ex);
void handle_equality(expr * lhs, expr * rhs);
@ -640,6 +644,7 @@ protected:
virtual void new_diseq_eh(theory_var, theory_var);
virtual theory* mk_fresh(context*) { return alloc(theory_str, get_manager(), m_params); }
virtual void init(context * ctx);
virtual void init_search_eh();
virtual void add_theory_assumptions(expr_ref_vector & assumptions);
virtual lbool validate_unsat_core(expr_ref_vector & unsat_core);