3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-29 20:05:51 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
nilsbecker 2018-04-15 20:57:28 +02:00
commit 984de9f98f
15 changed files with 1954 additions and 25 deletions

View file

@ -2680,6 +2680,12 @@ namespace z3 {
inline func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range) {
return range.ctx().function(name, d1, d2, d3, d4, d5, range);
}
inline func_decl function(char const* name, sort_vector const& domain, sort const& range) {
return range.ctx().function(name, domain, range);
}
inline func_decl function(std::string const& name, sort_vector const& domain, sort const& range) {
return range.ctx().function(name.c_str(), domain, range);
}
inline expr select(expr const & a, expr const & i) {
check_context(a, i);

View file

@ -1919,7 +1919,7 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref &
expr_ref pow_2_sbitsm1(m), m1(m);
pow_2_sbitsm1 = m_bv_util.mk_numeral(fu().fm().m_powers2(sbits - 1), sbits);
m1 = m_bv_util.mk_numeral(-1, ebits);
m1 = m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, ebits));
m_simp.mk_eq(a_sig, pow_2_sbitsm1, t1);
m_simp.mk_eq(a_exp, m1, t2);
m_simp.mk_and(t1, t2, tie);
@ -1927,7 +1927,7 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref &
m_simp.mk_and(tie, rm_is_rte, c421);
m_simp.mk_and(tie, rm_is_rta, c422);
c423 = m_bv_util.mk_sle(a_exp, m_bv_util.mk_numeral(-2, ebits));
c423 = m_bv_util.mk_sle(a_exp, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(2, ebits)));
dbg_decouple("fpa2bv_r2i_c421", c421);
dbg_decouple("fpa2bv_r2i_c422", c422);
@ -2452,7 +2452,7 @@ void fpa2bv_converter::mk_to_fp_float(sort * to_srt, expr * rm, expr * x, expr_r
const mpz & ovft = m_mpf_manager.m_powers2.m1(to_ebits+1, false);
first_ovf_exp = m_bv_util.mk_numeral(ovft, from_ebits+2);
first_udf_exp = m_bv_util.mk_concat(
m_bv_util.mk_numeral(-1, ebits_diff + 3),
m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, ebits_diff + 3)),
m_bv_util.mk_numeral(1, to_ebits + 1));
dbg_decouple("fpa2bv_to_float_first_ovf_exp", first_ovf_exp);
dbg_decouple("fpa2bv_to_float_first_udf_exp", first_udf_exp);
@ -3107,7 +3107,7 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex
expr_ref exp_bv(m), exp_all_ones(m);
exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result);
exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits));
exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, ebits)));
m_extra_assertions.push_back(exp_all_ones);
expr_ref sig_bv(m), sig_is_non_zero(m);
@ -3246,18 +3246,20 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
incd = m.mk_eq(rounding_decision, bv1);
pr_is_zero = m.mk_eq(pre_rounded, m_bv_util.mk_numeral(0, bv_sz + 3));
ovfl = m.mk_and(incd, pr_is_zero);
dbg_decouple("fpa2bv_to_bv_incd", incd);
dbg_decouple("fpa2bv_to_bv_ovfl", ovfl);
expr_ref ul(m), in_range(m);
if (!is_signed) {
ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz));
ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz)));
in_range = m.mk_and(m.mk_not(x_is_neg), m.mk_not(ovfl),
m_bv_util.mk_ule(pre_rounded, ul));
}
else {
expr_ref ll(m);
ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1)));
ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_numeral(-1, bv_sz-1));
ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_numeral(-1, bv_sz + 3)));
ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz-1)));
ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz + 3))));
in_range = m.mk_and(m.mk_not(ovfl),
m_bv_util.mk_sle(ll, pre_rounded),
m_bv_util.mk_sle(pre_rounded, ul));

View file

@ -773,7 +773,7 @@ br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & resu
if (m_fm.is_nan(v)) {
if (m_hi_fp_unspecified) {
expr * args[4] = { bu.mk_numeral(0, 1),
bu.mk_numeral(-1, x.get_ebits()),
bu.mk_bv_neg(bu.mk_numeral(1, x.get_ebits())),
bu.mk_numeral(0, x.get_sbits() - 2),
bu.mk_numeral(1, 1) };
result = bu.mk_concat(4, args);

View file

@ -200,6 +200,9 @@ void re2automaton::set_solver(expr_solver* solver) {
m_sa = alloc(symbolic_automata_t, sm, *m_ba.get());
}
eautomaton* re2automaton::mk_product(eautomaton* a1, eautomaton* a2) {
return m_sa->mk_product(*a1, *a2);
}
eautomaton* re2automaton::operator()(expr* e) {
eautomaton* r = re2aut(e);

View file

@ -53,7 +53,9 @@ public:
bool is_range() const { return m_ty == t_range; }
sort* get_sort() const { return m_sort; }
expr* get_char() const { SASSERT(is_char()); return m_t; }
expr* get_pred() const { SASSERT(is_pred()); return m_t; }
expr* get_lo() const { SASSERT(is_range()); return m_t; }
expr* get_hi() const { SASSERT(is_range()); return m_s; }
};
class sym_expr_manager {
@ -87,6 +89,7 @@ public:
~re2automaton();
eautomaton* operator()(expr* e);
void set_solver(expr_solver* solver);
eautomaton* mk_product(eautomaton *a1, eautomaton *a2);
};
/**

View file

@ -213,6 +213,9 @@ std::string zstring::encode() const {
else if (ch == '\\') {
strm << "\\\\";
}
else if (ch >= 128) {
strm << "\\x" << std::hex << (unsigned)ch << std::dec;
}
else {
strm << (char)(ch);
}

View file

@ -454,6 +454,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
func_decl* f = m_ar.get_as_array_func_decl(to_app(a));
func_interp* g = m_model.get_func_interp(f);
if (!g) return false;
unsigned sz = g->num_entries();
unsigned arity = f->get_arity();
unsigned base_sz = stores.size();

View file

@ -625,7 +625,7 @@ namespace datalog {
#if _WINDOWS
int converted = sscanf_s(s, "%I64u", &res);
#else
int converted = sscanf(s, "%llu", &res);
int converted = sscanf(s, "%I64u", &res);
#endif
if(converted==0) {
return false;

View file

@ -79,6 +79,12 @@ def_module_params(module_name='smt',
('theory_aware_branching', BOOL, False, 'Allow the context to use extra information from theory solvers regarding literal branching prioritization.'),
('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'),
('str.overlap_priority', DOUBLE, -0.1, 'theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true'),
('str.regex_automata', BOOL, True, 'use automata-based reasoning for regular expressions (Z3str3 only)'),
('str.regex_automata_difficulty_threshold', UINT, 1000, 'difficulty threshold for regex automata heuristics'),
('str.regex_automata_intersection_difficulty_threshold', UINT, 1000, 'difficulty threshold for regex intersection heuristics'),
('str.regex_automata_failed_automaton_threshold', UINT, 10, 'number of failed automaton construction attempts after which a full automaton is automatically built'),
('str.regex_automata_failed_intersection_threshold', UINT, 10, 'number of failed automaton intersection attempts after which intersection is always computed'),
('str.regex_automata_length_attempt_threshold', UINT, 10, 'number of length/path constraint attempts before checking unsatisfiability of regex terms'),
('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'),
('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'),
('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'),

View file

@ -31,4 +31,10 @@ void theory_str_params::updt_params(params_ref const & _p) {
m_UseBinarySearch = p.str_use_binary_search();
m_BinarySearchInitialUpperBound = p.str_binary_search_start();
m_OverlapTheoryAwarePriority = p.str_overlap_priority();
m_RegexAutomata = p.str_regex_automata();
m_RegexAutomata_DifficultyThreshold = p.str_regex_automata_difficulty_threshold();
m_RegexAutomata_IntersectionDifficultyThreshold = p.str_regex_automata_intersection_difficulty_threshold();
m_RegexAutomata_FailedAutomatonThreshold = p.str_regex_automata_failed_automaton_threshold();
m_RegexAutomata_FailedIntersectionThreshold = p.str_regex_automata_failed_intersection_threshold();
m_RegexAutomata_LengthAttemptThreshold = p.str_regex_automata_length_attempt_threshold();
}

View file

@ -80,6 +80,43 @@ struct theory_str_params {
double m_OverlapTheoryAwarePriority;
/*
* If RegexAutomata is set to true,
* Z3str3 will use automata-based methods to reason about
* regular expression constraints.
*/
bool m_RegexAutomata;
/*
* RegexAutomata_DifficultyThreshold is the lowest difficulty above which Z3str3
* will not eagerly construct an automaton for a regular expression term.
*/
unsigned m_RegexAutomata_DifficultyThreshold;
/*
* RegexAutomata_IntersectionDifficultyThreshold is the lowest difficulty above which Z3str3
* will not eagerly intersect automata to check unsatisfiability.
*/
unsigned m_RegexAutomata_IntersectionDifficultyThreshold;
/*
* RegexAutomata_FailedAutomatonThreshold is the number of failed attempts to build an automaton
* after which a full automaton (i.e. with no length information) will be built regardless of difficulty.
*/
unsigned m_RegexAutomata_FailedAutomatonThreshold;
/*
* RegexAutomaton_FailedIntersectionThreshold is the number of failed attempts to perform automaton
* intersection after which intersection will always be performed regardless of difficulty.
*/
unsigned m_RegexAutomata_FailedIntersectionThreshold;
/*
* RegexAutomaton_LengthAttemptThreshold is the number of attempts to satisfy length/path constraints
* before which we begin checking unsatisfiability of a regex term.
*/
unsigned m_RegexAutomata_LengthAttemptThreshold;
theory_str_params(params_ref const & p = params_ref()):
m_StrongArrangements(true),
m_AggressiveLengthTesting(false),
@ -91,7 +128,13 @@ struct theory_str_params {
m_FiniteOverlapModels(false),
m_UseBinarySearch(false),
m_BinarySearchInitialUpperBound(64),
m_OverlapTheoryAwarePriority(-0.1)
m_OverlapTheoryAwarePriority(-0.1),
m_RegexAutomata(true),
m_RegexAutomata_DifficultyThreshold(1000),
m_RegexAutomata_IntersectionDifficultyThreshold(1000),
m_RegexAutomata_FailedAutomatonThreshold(10),
m_RegexAutomata_FailedIntersectionThreshold(10),
m_RegexAutomata_LengthAttemptThreshold(10)
{
updt_params(p);
}

View file

@ -446,7 +446,16 @@ namespace smt {
expr* arg = atom->get_arg(i);
literal l = compile_arg(arg);
numeral c = m_util.get_coeff(atom, i);
args.push_back(std::make_pair(l, c));
switch (ctx.get_assignment(l)) {
case l_true:
k -= c;
break;
case l_false:
break;
default:
args.push_back(std::make_pair(l, c));
break;
}
}
if (m_util.is_at_most_k(atom) || m_util.is_le(atom)) {
// turn W <= k into -W >= -k
@ -458,7 +467,7 @@ namespace smt {
else {
SASSERT(m_util.is_at_least_k(atom) || m_util.is_ge(atom) || m_util.is_eq(atom));
}
TRACE("pb", display(tout, *c););
TRACE("pb", display(tout, *c, true););
//app_ref fml1(m), fml2(m);
//fml1 = c->to_expr(ctx, m);
c->unique();

File diff suppressed because it is too large Load diff

View file

@ -20,9 +20,11 @@
#include "util/trail.h"
#include "util/union_find.h"
#include "util/scoped_ptr_vector.h"
#include "util/hashtable.h"
#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"
@ -36,6 +38,7 @@
namespace smt {
typedef hashtable<symbol, symbol_hash_proc, symbol_eq_proc> symbol_set;
typedef int_hashtable<int_hash, default_eq<int> > integer_set;
class str_value_factory : public value_factory {
seq_util u;
@ -148,6 +151,70 @@ public:
bool matches(zstring input);
};
class regex_automaton_under_assumptions {
protected:
expr * re_term;
eautomaton * aut;
bool polarity;
bool assume_lower_bound;
rational lower_bound;
bool assume_upper_bound;
rational upper_bound;
public:
regex_automaton_under_assumptions() :
re_term(NULL), aut(NULL), polarity(false),
assume_lower_bound(false), assume_upper_bound(false) {}
regex_automaton_under_assumptions(expr * re_term, eautomaton * aut, bool polarity) :
re_term(re_term), aut(aut), polarity(polarity),
assume_lower_bound(false), assume_upper_bound(false) {}
void set_lower_bound(rational & lb) {
lower_bound = lb;
assume_lower_bound = true;
}
void unset_lower_bound() {
assume_lower_bound = false;
}
void set_upper_bound(rational & ub) {
upper_bound = ub;
assume_upper_bound = true;
}
void unset_upper_bound() {
assume_upper_bound = false;
}
bool get_lower_bound(rational & lb) const {
if (assume_lower_bound) {
lb = lower_bound;
return true;
} else {
return false;
}
}
bool get_upper_bound(rational & ub) const {
if (assume_upper_bound) {
ub = upper_bound;
return true;
} else {
return false;
}
}
eautomaton * get_automaton() const { return aut; }
expr * get_regex_term() const { return re_term; }
bool get_polarity() const { return polarity; }
virtual ~regex_automaton_under_assumptions() {
// don't free str_in_re or aut;
// they are managed separately
}
};
class theory_str : public theory {
struct T_cut
{
@ -250,6 +317,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;
@ -267,6 +336,10 @@ protected:
// enode lists for library-aware/high-level string terms (e.g. substr, contains)
ptr_vector<enode> m_library_aware_axiom_todo;
// list of axioms that are re-asserted every time the scope is popped
expr_ref_vector m_persisted_axioms;
expr_ref_vector m_persisted_axiom_todo;
// hashtable of all exprs for which we've already set up term-specific axioms --
// this prevents infinite recursive descent with respect to axioms that
// include an occurrence of the term for which axioms are being generated
@ -320,7 +393,31 @@ protected:
// TBD: do a curried map for determinism.
std::map<std::pair<expr*, zstring>, expr*> regex_in_bool_map;
obj_map<expr, std::set<zstring> > regex_in_var_reg_str_map;
// regex automata
scoped_ptr_vector<eautomaton> m_automata;
ptr_vector<eautomaton> regex_automata;
obj_hashtable<expr> regex_terms;
obj_map<expr, ptr_vector<expr> > regex_terms_by_string; // S --> [ (str.in.re S *) ]
obj_map<expr, svector<regex_automaton_under_assumptions> > regex_automaton_assumptions; // RegEx --> [ aut+assumptions ]
obj_map<expr, nfa> regex_nfa_cache; // Regex term --> NFA
obj_hashtable<expr> regex_terms_with_path_constraints; // set of string terms which have had path constraints asserted in the current scope
obj_hashtable<expr> regex_terms_with_length_constraints; // set of regex terms which had had length constraints asserted in the current scope
obj_map<expr, expr*> regex_term_to_length_constraint; // (str.in.re S R) -> (length constraint over S wrt. R)
obj_map<expr, ptr_vector<expr> > regex_term_to_extra_length_vars; // extra length vars used in regex_term_to_length_constraint entries
// keep track of the last lower/upper bound we saw for each string term
// so we don't perform duplicate work
obj_map<expr, rational> regex_last_lower_bound;
obj_map<expr, rational> regex_last_upper_bound;
// each counter maps a (str.in.re) expression to an integer.
// use helper functions regex_inc_counter() and regex_get_counter() to access
obj_map<expr, unsigned> regex_length_attempt_count;
obj_map<expr, unsigned> regex_fail_count;
obj_map<expr, unsigned> regex_intersection_fail_count;
obj_map<expr, ptr_vector<expr> > string_chars; // S --> [S_0, S_1, ...] for character terms S_i
svector<char> char_set;
std::map<char, int> charSetLookupTable;
@ -439,14 +536,32 @@ protected:
void instantiate_axiom_str_to_int(enode * e);
void instantiate_axiom_int_to_str(enode * e);
void add_persisted_axiom(expr * a);
expr * mk_RegexIn(expr * str, expr * regexp);
void instantiate_axiom_RegexIn(enode * e);
app * mk_unroll(expr * n, expr * bound);
void process_unroll_eq_const_str(expr * unrollFunc, expr * constStr);
void unroll_str2reg_constStr(expr * unrollFunc, expr * eqConstStr);
void process_concat_eq_unroll(expr * concat, expr * unroll);
// regex automata and length-aware regex
unsigned estimate_regex_complexity(expr * re);
unsigned estimate_regex_complexity_under_complement(expr * re);
unsigned estimate_automata_intersection_difficulty(eautomaton * aut1, eautomaton * aut2);
bool check_regex_length_linearity(expr * re);
bool check_regex_length_linearity_helper(expr * re, bool already_star);
expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables);
void check_subterm_lengths(expr * re, integer_set & lens);
void find_automaton_initial_bounds(expr * str_in_re, eautomaton * aut);
bool refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound);
bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound);
expr_ref generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal, expr_ref & characterConstraints);
void aut_path_add_next(u_map<expr*>& next, expr_ref_vector& trail, unsigned idx, expr* cond);
expr_ref aut_path_rewrite_constraint(expr * cond, expr * ch_var);
void regex_inc_counter(obj_map<expr, unsigned> & counter_map, expr * key);
unsigned regex_get_counter(obj_map<expr, unsigned> & counter_map, expr * key);
void set_up_axioms(expr * ex);
void handle_equality(expr * lhs, expr * rhs);
@ -535,6 +650,7 @@ protected:
std::map<expr*, std::map<expr*, int> > & concat_eq_concat_map,
std::map<expr*, std::set<expr*> > & unrollGroupMap);
bool term_appears_as_subterm(expr * needle, expr * haystack);
void classify_ast_by_type(expr * node, std::map<expr*, int> & varMap,
std::map<expr*, int> & concatMap, std::map<expr*, int> & unrollMap);
void classify_ast_by_type_in_positive_context(std::map<expr*, int> & varMap,
@ -623,6 +739,7 @@ protected:
void new_diseq_eh(theory_var, theory_var) override;
theory* mk_fresh(context*) override { return alloc(theory_str, get_manager(), m_params); }
void init(context * ctx) override;
void init_search_eh() override;
void add_theory_assumptions(expr_ref_vector & assumptions) override;
lbool validate_unsat_core(expr_ref_vector & unsat_core) override;

View file

@ -93,7 +93,7 @@ class fpa2bv_tactic : public tactic {
expr * sgn, *sig, *exp;
m_conv.split_fp(new_curr, sgn, exp, sig);
result.back()->assert_expr(m.mk_eq(sgn, m_conv.bu().mk_numeral(0, 1)));
result.back()->assert_expr(m.mk_eq(exp, m_conv.bu().mk_numeral(-1, m_conv.bu().get_bv_size(exp))));
result.back()->assert_expr(m.mk_eq(exp, m_conv.bu().mk_bv_neg(m_conv.bu().mk_numeral(1, m_conv.bu().get_bv_size(exp)))));
result.back()->assert_expr(m.mk_eq(sig, m_conv.bu().mk_numeral(1, m_conv.bu().get_bv_size(sig))));
}
}