mirror of
https://github.com/Z3Prover/z3
synced 2025-06-06 06:03:23 +00:00
length estimation
This commit is contained in:
parent
fbe8d1577e
commit
a5c828f6f2
2 changed files with 121 additions and 2 deletions
|
@ -25,6 +25,8 @@
|
||||||
#include "smt/theory_seq_empty.h"
|
#include "smt/theory_seq_empty.h"
|
||||||
#include "smt/theory_arith.h"
|
#include "smt/theory_arith.h"
|
||||||
#include "ast/ast_util.h"
|
#include "ast/ast_util.h"
|
||||||
|
#include "seq_rewriter.h"
|
||||||
|
#include "smt_kernel.h"
|
||||||
|
|
||||||
namespace smt {
|
namespace smt {
|
||||||
|
|
||||||
|
@ -48,6 +50,7 @@ namespace smt {
|
||||||
finalCheckProgressIndicator(false),
|
finalCheckProgressIndicator(false),
|
||||||
m_trail(m),
|
m_trail(m),
|
||||||
m_factory(nullptr),
|
m_factory(nullptr),
|
||||||
|
m_mk_aut(m),
|
||||||
m_unused_id(0),
|
m_unused_id(0),
|
||||||
m_delayed_axiom_setup_terms(m),
|
m_delayed_axiom_setup_terms(m),
|
||||||
tmpStringVarCount(0),
|
tmpStringVarCount(0),
|
||||||
|
@ -95,6 +98,26 @@ namespace smt {
|
||||||
return u.str.mk_string(sym);
|
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() {
|
void theory_str::initialize_charset() {
|
||||||
bool defaultCharset = true;
|
bool defaultCharset = true;
|
||||||
if (defaultCharset) {
|
if (defaultCharset) {
|
||||||
|
@ -1718,6 +1741,11 @@ namespace smt {
|
||||||
regex_in_var_reg_str_map[ex->get_arg(0)].insert(regexStr);
|
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);
|
expr_ref str(ex->get_arg(0), m);
|
||||||
app * regex = to_app(ex->get_arg(1));
|
app * regex = to_app(ex->get_arg(1));
|
||||||
|
|
||||||
|
@ -1887,7 +1915,7 @@ namespace smt {
|
||||||
check_contain_in_new_eq(lhs, rhs);
|
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;);
|
TRACE("str", tout << "checking regex consistency" << std::endl;);
|
||||||
check_regex_in(lhs, rhs);
|
check_regex_in(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
@ -6550,6 +6578,92 @@ namespace smt {
|
||||||
return 1;
|
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()
|
* strArgmt::solve_concat_eq_str()
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "ast/ast_pp.h"
|
#include "ast/ast_pp.h"
|
||||||
#include "ast/arith_decl_plugin.h"
|
#include "ast/arith_decl_plugin.h"
|
||||||
#include "ast/rewriter/th_rewriter.h"
|
#include "ast/rewriter/th_rewriter.h"
|
||||||
|
#include "ast/rewriter/seq_rewriter.h"
|
||||||
#include "ast/seq_decl_plugin.h"
|
#include "ast/seq_decl_plugin.h"
|
||||||
#include "smt/smt_theory.h"
|
#include "smt/smt_theory.h"
|
||||||
#include "smt/params/theory_str_params.h"
|
#include "smt/params/theory_str_params.h"
|
||||||
|
@ -267,6 +268,8 @@ protected:
|
||||||
|
|
||||||
str_value_factory * m_factory;
|
str_value_factory * m_factory;
|
||||||
|
|
||||||
|
re2automaton m_mk_aut;
|
||||||
|
|
||||||
// Unique identifier appended to unused variables to ensure that model construction
|
// Unique identifier appended to unused variables to ensure that model construction
|
||||||
// does not introduce equalities when they weren't enforced.
|
// does not introduce equalities when they weren't enforced.
|
||||||
unsigned m_unused_id;
|
unsigned m_unused_id;
|
||||||
|
@ -461,9 +464,10 @@ protected:
|
||||||
void unroll_str2reg_constStr(expr * unrollFunc, expr * eqConstStr);
|
void unroll_str2reg_constStr(expr * unrollFunc, expr * eqConstStr);
|
||||||
void process_concat_eq_unroll(expr * concat, expr * unroll);
|
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(expr * re);
|
||||||
unsigned estimate_regex_complexity_under_complement(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 set_up_axioms(expr * ex);
|
||||||
void handle_equality(expr * lhs, expr * rhs);
|
void handle_equality(expr * lhs, expr * rhs);
|
||||||
|
@ -640,6 +644,7 @@ protected:
|
||||||
virtual void new_diseq_eh(theory_var, theory_var);
|
virtual void new_diseq_eh(theory_var, theory_var);
|
||||||
|
|
||||||
virtual theory* mk_fresh(context*) { return alloc(theory_str, get_manager(), m_params); }
|
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 init_search_eh();
|
||||||
virtual void add_theory_assumptions(expr_ref_vector & assumptions);
|
virtual void add_theory_assumptions(expr_ref_vector & assumptions);
|
||||||
virtual lbool validate_unsat_core(expr_ref_vector & unsat_core);
|
virtual lbool validate_unsat_core(expr_ref_vector & unsat_core);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue