From 53f72d9cbe310f2d2fbc509127fb369de957058b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Jan 2022 15:44:49 -0800 Subject: [PATCH 001/258] updated mini Signed-off-by: Nikolaj Bjorner --- examples/python/mini_ic3.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/python/mini_ic3.py b/examples/python/mini_ic3.py index b7b732459..31d3c595b 100644 --- a/examples/python/mini_ic3.py +++ b/examples/python/mini_ic3.py @@ -162,6 +162,9 @@ class Goal: self.cube = cube self.parent = parent + def __lt__(self, other): + return self.level < other.level + def is_seq(f): return isinstance(f, list) or isinstance(f, tuple) or isinstance(f, AstVector) @@ -210,12 +213,12 @@ class MiniIC3: def next(self, f): if is_seq(f): return [self.next(f1) for f1 in f] - return substitute(f, zip(self.x0, self.xn)) + return substitute(f, [p for p in zip(self.x0, self.xn)]) def prev(self, f): if is_seq(f): return [self.prev(f1) for f1 in f] - return substitute(f, zip(self.xn, self.x0)) + return substitute(f, [p for p in zip(self.xn, self.x0)]) def add_solver(self): s = fd_solver() From 461e71017d87ac3d72157030ac278398416a7b4f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Jan 2022 15:54:44 -0800 Subject: [PATCH 002/258] fix #5792 again Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 356e30d1a..dcd3ff234 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2820,12 +2820,14 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, if (!is_num1 || !is_num2) return BR_FAILED; - + + bool sign0 = m_util.has_sign_bit(a0_val, bv_sz); + bool sign1 = m_util.has_sign_bit(a1_val, bv_sz); + if (sign0) a0_val = rational::power_of_two(bv_sz) - a0_val; + if (sign1) a1_val = rational::power_of_two(bv_sz) - a1_val; rational lim = rational::power_of_two(bv_sz); rational r = a0_val * a1_val; - bool sign1 = m_util.has_sign_bit(a0_val, bv_sz); - bool sign2 = m_util.has_sign_bit(a1_val, bv_sz); - result = m().mk_bool_val((sign1 != sign2) || r < lim); + result = m().mk_bool_val((sign0 != sign1) || r < lim); return BR_DONE; } From a6210413086c7889dac7752dddbe38e7b172f785 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Jan 2022 10:45:38 -0800 Subject: [PATCH 003/258] fix #5795 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 80432450d..b7547b990 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2627,7 +2627,8 @@ namespace z3 { Z3_solver m_solver; void init(Z3_solver s) { m_solver = s; - Z3_solver_inc_ref(ctx(), s); + if (s) + Z3_solver_inc_ref(ctx(), s); } public: struct simple {}; @@ -2636,7 +2637,7 @@ namespace z3 { solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); } solver(context & c, Z3_solver s):object(c) { init(s); } solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); } - solver(context & c, solver const& src, translate): object(c) { init(Z3_solver_translate(src.ctx(), src, c)); } + solver(context & c, solver const& src, translate): object(c) { Z3_solver s = Z3_solver_translate(src.ctx(), src, c); check_error(); init(s); } solver(solver const & s):object(s) { init(s.m_solver); } ~solver() { Z3_solver_dec_ref(ctx(), m_solver); } operator Z3_solver() const { return m_solver; } From 4da930b4909bc19530a59d7494f79c9f78bbac8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Jan 2022 10:50:48 -0800 Subject: [PATCH 004/258] #5794 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index dcd3ff234..f1b0afd45 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2809,6 +2809,10 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_num1 = is_numeral(args[0], a0_val, bv_sz); bool is_num2 = is_numeral(args[1], a1_val, bv_sz); + if (bv_sz == 1) { + result = m().mk_bool_val(!(a0_val.is_one() && a1_val.is_one())); + return BR_DONE; + } if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) { result = m().mk_true(); return BR_DONE; From 9e5b6e0c9c8abb8c3ecb4f0d93bcc51146659218 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Jan 2022 12:12:58 -0800 Subject: [PATCH 005/258] #5778 --- src/sat/smt/array_axioms.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 296c35b8c..c0f0e9a72 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -556,7 +556,7 @@ namespace array { bool has_default = false; for (euf::enode* p : euf::enode_parents(n)) has_default |= a.is_default(p->get_expr()); - if (has_default) + if (!has_default) propagate_parent_default(v); } From 5e81c1220c959fe74f5b4af7ab7b340b4a9d1845 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Jan 2022 12:48:15 -0800 Subject: [PATCH 006/258] #5797 probably still wrong wrt underflow. --- src/ast/rewriter/bv_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index f1b0afd45..4d15011d6 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2829,7 +2829,7 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool sign1 = m_util.has_sign_bit(a1_val, bv_sz); if (sign0) a0_val = rational::power_of_two(bv_sz) - a0_val; if (sign1) a1_val = rational::power_of_two(bv_sz) - a1_val; - rational lim = rational::power_of_two(bv_sz); + rational lim = rational::power_of_two(bv_sz-1); rational r = a0_val * a1_val; result = m().mk_bool_val((sign0 != sign1) || r < lim); return BR_DONE; From 25516319573eaf1cd4da1ae20e039973c959a086 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 29 Jan 2022 09:15:38 -0800 Subject: [PATCH 007/258] mul overflow #5797 --- src/ast/rewriter/bv_rewriter.cpp | 50 +++++--------------------------- src/ast/rewriter/bv_rewriter.h | 3 +- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 4d15011d6..2c0d6abfb 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -196,11 +196,11 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons SASSERT(num_args == 1); return mk_bit2bool(args[0], f->get_parameter(0).get_int(), result); case OP_BSMUL_NO_OVFL: - return mk_bvsmul_no_overflow(num_args, args, result); + return mk_bvsmul_no_overflow(num_args, args, true, result); + case OP_BSMUL_NO_UDFL: + return mk_bvsmul_no_overflow(num_args, args, false, result); case OP_BUMUL_NO_OVFL: return mk_bvumul_no_overflow(num_args, args, result); - case OP_BSMUL_NO_UDFL: - return mk_bvsmul_no_underflow(num_args, args, result); default: return BR_FAILED; } @@ -2802,22 +2802,19 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu return BR_FAILED; } -br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result) { +br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result) { SASSERT(num == 2); unsigned bv_sz; rational a0_val, a1_val; bool is_num1 = is_numeral(args[0], a0_val, bv_sz); bool is_num2 = is_numeral(args[1], a1_val, bv_sz); - if (bv_sz == 1) { - result = m().mk_bool_val(!(a0_val.is_one() && a1_val.is_one())); - return BR_DONE; - } - if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) { + + if (is_num1 && (a0_val.is_zero() || (bv_sz != 1 && a0_val.is_one()))) { result = m().mk_true(); return BR_DONE; } - if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) { + if (is_num2 && (a1_val.is_zero() || (bv_sz != 1 && a1_val.is_one()))) { result = m().mk_true(); return BR_DONE; } @@ -2831,7 +2828,7 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, if (sign1) a1_val = rational::power_of_two(bv_sz) - a1_val; rational lim = rational::power_of_two(bv_sz-1); rational r = a0_val * a1_val; - result = m().mk_bool_val((sign0 != sign1) || r < lim); + result = m().mk_bool_val((is_overflow == (sign0 != sign1)) || r < lim); return BR_DONE; } @@ -2861,36 +2858,5 @@ br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args, return BR_FAILED; } -br_status bv_rewriter::mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 2); - unsigned bv_sz; - rational a0_val, a1_val; - - bool is_num1 = is_numeral(args[0], a0_val, bv_sz); - bool is_num2 = is_numeral(args[1], a1_val, bv_sz); - if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) { - result = m().mk_true(); - return BR_DONE; - } - if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) { - result = m().mk_true(); - return BR_DONE; - } - - if (is_num1 && is_num2) { - rational ul = rational::power_of_two(bv_sz); - rational lim = rational::power_of_two(bv_sz-1); - if (a0_val >= lim) a0_val -= ul; - if (a1_val >= lim) a1_val -= ul; - rational mr = a0_val * a1_val; - rational neg_lim = -lim; - TRACE("bv_rewriter_bvsmul_no_underflow", tout << "a0:" << a0_val << " a1:" << a1_val << " mr:" << mr << " neg_lim:" << neg_lim << std::endl;); - result = m().mk_bool_val(mr >= neg_lim); - return BR_DONE; - } - - return BR_FAILED; -} - template class poly_rewriter; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index e9596256f..7b734dca1 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -134,9 +134,8 @@ class bv_rewriter : public poly_rewriter { br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result); br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result); br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result); - br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result); + br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result); br_status mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result); - br_status mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result); bool is_minus_one_times_t(expr * arg); void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result); From 913b90f7aac8a585a40a0c74d7837be8dc2cb807 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 30 Jan 2022 10:42:34 -0800 Subject: [PATCH 008/258] fix #5802 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 2c0d6abfb..d7ba4d604 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2828,7 +2828,10 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, if (sign1) a1_val = rational::power_of_two(bv_sz) - a1_val; rational lim = rational::power_of_two(bv_sz-1); rational r = a0_val * a1_val; - result = m().mk_bool_val((is_overflow == (sign0 != sign1)) || r < lim); + if (is_overflow) + result = m().mk_bool_val(sign0 != sign1 || r < lim); + else + result = m().mk_bool_val(sign0 == sign1 || r <= lim); return BR_DONE; } From 773e829c581ab99d9e24d8e3a28bc78ce7743f7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 10:16:09 -0800 Subject: [PATCH 009/258] #5804 --- src/ast/rewriter/seq_rewriter.cpp | 57 ++++++++++++++----------------- src/ast/rewriter/seq_rewriter.h | 1 + 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index adaf3ec0f..18af6a239 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -5531,44 +5531,37 @@ lbool seq_rewriter::eq_length(expr* x, expr* y) { maximal length (the sequence is bounded). */ -bool seq_rewriter::min_length(expr* e, unsigned& len) { +bool seq_rewriter::min_length(unsigned sz, expr* const* ss, unsigned& len) { + ptr_buffer es; + for (unsigned i = 0; i < sz; ++i) + es.push_back(ss[i]); zstring s; len = 0; - if (str().is_unit(e)) { - len = 1; - return true; + bool bounded = true; + while (!es.empty()) { + expr* e = es.back(); + es.pop_back(); + if (str().is_unit(e)) + len += 1; + else if (str().is_empty(e)) + continue; + else if (str().is_string(e, s)) + len += s.length(); + else if (str().is_concat(e)) + for (expr* arg : *to_app(e)) + es.push_back(arg); + else + bounded = false; } - else if (str().is_empty(e)) { - len = 0; - return true; - } - else if (str().is_string(e, s)) { - len = s.length(); - return true; - } - else if (str().is_concat(e)) { - unsigned min_l = 0; - bool bounded = true; - for (expr* arg : *to_app(e)) { - if (!min_length(arg, min_l)) - bounded = false; - len += min_l; - } - return bounded; - } - return false; + return bounded; +} + +bool seq_rewriter::min_length(expr* e, unsigned& len) { + return min_length(1, &e, len); } bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) { - unsigned min_l = 0; - bool bounded = true; - len = 0; - for (expr* arg : es) { - if (!min_length(arg, min_l)) - bounded = false; - len += min_l; - } - return bounded; + return min_length(es.size(), es.data(), len); } bool seq_rewriter::max_length(expr* e, rational& len) { diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 0d8ac029c..f10532572 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -322,6 +322,7 @@ class seq_rewriter { bool reduce_eq_empty(expr* l, expr* r, expr_ref& result); bool min_length(expr_ref_vector const& es, unsigned& len); bool min_length(expr* e, unsigned& len); + bool min_length(unsigned sz, expr* const* es, unsigned& len); bool max_length(expr* e, rational& len); lbool eq_length(expr* x, expr* y); expr* concat_non_empty(expr_ref_vector& es); From a189ca8b60eb06705fb5e1458ebdaa82be5ec98b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 10:50:46 -0800 Subject: [PATCH 010/258] truncation directive #5805 --- src/api/api_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8e8360cd3..43211b3b8 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -114,7 +114,7 @@ extern "C" { } solver2smt2_pp::solver2smt2_pp(ast_manager& m, const std::string& file): - m_pp_util(m), m_out(file), m_tracked(m) { + m_pp_util(m), m_out(file, std::ofstream::trunc | std::ofstream::out), m_tracked(m) { if (!m_out) { throw default_exception("could not open " + file + " for output"); } From a326ad4cd9a345547708672b676435f2723fbe10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 11:54:06 -0800 Subject: [PATCH 011/258] flag incomplete on lambdas #5803 --- src/smt/smt_context.cpp | 21 +++++++++++++++------ src/smt/smt_context.h | 1 + src/smt/smt_context_pp.cpp | 3 +++ src/smt/smt_failure.h | 1 + src/smt/smt_internalizer.cpp | 2 ++ src/smt/theory_array_full.cpp | 1 - 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index d659329ca..60eccf962 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3731,7 +3731,7 @@ namespace smt { if (status == l_false) { return false; } - if (status == l_true && !m_qmanager->has_quantifiers()) { + if (status == l_true && !m_qmanager->has_quantifiers() && !m_has_lambda) { return false; } if (status == l_true && m_qmanager->has_quantifiers()) { @@ -3754,6 +3754,11 @@ namespace smt { break; } } + if (status == l_true && m_has_lambda) { + m_last_search_failure = LAMBDAS; + status = l_undef; + return false; + } inc_limits(); if (status == l_true || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) { SASSERT(!inconsistent()); @@ -3765,13 +3770,13 @@ namespace smt { pop_scope(m_scope_lvl - curr_lvl); SASSERT(at_search_level()); } - for (theory* th : m_theory_set) { - if (!inconsistent()) th->restart_eh(); - } + for (theory* th : m_theory_set) + if (!inconsistent()) + th->restart_eh(); + TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); - if (!inconsistent()) { + if (!inconsistent()) m_qmanager->restart_eh(); - } if (inconsistent()) { VERIFY(!resolve_conflict()); status = l_false; @@ -3993,6 +3998,10 @@ namespace smt { TRACE("final_check_step", tout << "RESULT final_check: " << result << "\n";); if (result == FC_GIVEUP && f != OK) m_last_search_failure = f; + if (result == FC_DONE && m_has_lambda) { + m_last_search_failure = LAMBDAS; + result = FC_GIVEUP; + } return result; } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index fd6c12482..89b94412d 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -773,6 +773,7 @@ namespace smt { void internalize_quantifier(quantifier * q, bool gate_ctx); + bool m_has_lambda = false; void internalize_lambda(quantifier * q); void internalize_formula_core(app * n, bool gate_ctx); diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 4499752e5..181d9d529 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -56,6 +56,8 @@ namespace smt { return out; case QUANTIFIERS: return out << "QUANTIFIERS"; + case LAMBDAS: + return out << "LAMBDAS"; } UNREACHABLE(); return out << "?"; @@ -79,6 +81,7 @@ namespace smt { } case RESOURCE_LIMIT: r = "(resource limits reached)"; break; case QUANTIFIERS: r = "(incomplete quantifiers)"; break; + case LAMBDAS: r = "(incomplete lambdas)"; break; case UNKNOWN: r = m_unknown; break; } return r; diff --git a/src/smt/smt_failure.h b/src/smt/smt_failure.h index ab5f0827b..ab706297f 100644 --- a/src/smt/smt_failure.h +++ b/src/smt/smt_failure.h @@ -31,6 +31,7 @@ namespace smt { NUM_CONFLICTS, //!< Maximum number of conflicts was reached THEORY, //!< Theory is incomplete RESOURCE_LIMIT, + LAMBDAS, //!< Logical context contains lambdas. QUANTIFIERS //!< Logical context contains universal quantifiers. }; diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 1c899ef18..525d0075e 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -605,6 +605,8 @@ namespace smt { bool_var bv = get_bool_var(fa); assign(literal(bv, false), nullptr); mark_as_relevant(bv); + push_trail(value_trail(m_has_lambda)); + m_has_lambda = true; } /** diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 6e7403737..4d1f358bf 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -763,7 +763,6 @@ namespace smt { app_ref sel1(m), sel2(m); sel1 = mk_select(args1); sel2 = mk_select(args2); - std::cout << "small domain " << sel1 << " " << sel2 << "\n"; is_new = try_assign_eq(sel1, sel2); #endif } From 62bb234251916dd7ef95f5c101742c1c770415c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 11:56:44 -0800 Subject: [PATCH 012/258] expose extract roots as separate --- src/sat/sat_scc.cpp | 35 +++++++++++++++++++++-------------- src/sat/sat_scc.h | 4 ++++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index e7adc33ec..c21f67ce5 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -67,15 +67,8 @@ namespace sat { } }; - unsigned scc::operator()() { - if (m_solver.m_inconsistent) - return 0; - if (!m_scc) - return 0; - CASSERT("scc_bug", m_solver.check_invariant()); - report rpt(*this); - TRACE("scc", m_solver.display(tout);); - TRACE("scc_details", m_solver.display_watches(tout);); + bool scc::extract_roots(literal_vector& roots, bool_var_vector& to_elim) { + literal_vector lits; unsigned_vector index; unsigned_vector lowlink; unsigned_vector s; @@ -84,11 +77,9 @@ namespace sat { index.resize(num_lits, UINT_MAX); lowlink.resize(num_lits, UINT_MAX); in_s.resize(num_lits, false); - literal_vector roots, lits; roots.resize(m_solver.num_vars(), null_literal); unsigned next_index = 0; svector frames; - bool_var_vector to_elim; for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { if (index[l_idx] != UINT_MAX) @@ -182,7 +173,7 @@ namespace sat { j--; if (to_literal(l2_idx) == ~l) { m_solver.set_conflict(); - return 0; + return false; } if (m_solver.is_external(to_literal(l2_idx).var())) { r = to_literal(l2_idx); @@ -226,6 +217,23 @@ namespace sat { roots[i] = literal(i, false); } } + return true; + } + + + unsigned scc::operator()() { + if (m_solver.m_inconsistent) + return 0; + if (!m_scc) + return 0; + CASSERT("scc_bug", m_solver.check_invariant()); + report rpt(*this); + TRACE("scc", m_solver.display(tout);); + TRACE("scc_details", m_solver.display_watches(tout);); + literal_vector roots; + bool_var_vector to_elim; + if (!extract_roots(roots, to_elim)) + return 0; TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; } tout << "to_elim: "; for (unsigned v : to_elim) tout << v << " "; tout << "\n";); m_num_elim += to_elim.size(); @@ -234,9 +242,8 @@ namespace sat { TRACE("scc_detail", m_solver.display(tout);); CASSERT("scc_bug", m_solver.check_invariant()); - if (m_scc_tr) { + if (m_scc_tr) reduce_tr(); - } TRACE("scc_detail", m_solver.display(tout);); return to_elim.size(); } diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index 0554e09d4..af239c53d 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -41,9 +41,13 @@ namespace sat { void reduce_tr(); unsigned reduce_tr(bool learned); + public: scc(solver & s, params_ref const & p); + + bool extract_roots(literal_vector& roots, bool_var_vector& lits); + unsigned operator()(); void updt_params(params_ref const & p); From 6422b783b2ba984c20152bcceb600b015acc8deb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 11:57:16 -0800 Subject: [PATCH 013/258] fix mux extraction to check for top-level assertion --- src/sat/smt/pb_solver.cpp | 46 +++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 5c67a05c5..5e63f19ad 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -21,6 +21,7 @@ Author: #include "sat/smt/pb_solver.h" #include "sat/smt/euf_solver.h" #include "sat/sat_simplifier_params.hpp" +#include "sat/sat_scc.h" namespace pb { @@ -1422,7 +1423,7 @@ namespace pb { c->watch_literal(*this, ~lit); } if (!c->well_formed()) - std::cout << *c << "\n"; + IF_VERBOSE(0, verbose_stream() << *c << "\n"); VERIFY(c->well_formed()); if (m_solver && m_solver->get_config().m_drat) { std::function fn = [&](std::ostream& out) { @@ -3133,32 +3134,35 @@ namespace pb { void solver::find_mutexes(literal_vector& lits, vector & mutexes) { sat::literal_set slits(lits); bool change = false; + for (constraint* cp : m_constraints) { - if (!cp->is_card()) continue; + if (!cp->is_card()) + continue; + if (cp->lit() != sat::null_literal) + continue; card const& c = cp->to_card(); - if (c.size() == c.k() + 1) { - literal_vector mux; - for (literal lit : c) { - if (slits.contains(~lit)) { - mux.push_back(~lit); - } - } - if (mux.size() <= 1) { - continue; - } + if (c.size() != c.k() + 1) + continue; - for (literal m : mux) { - slits.remove(m); - } - change = true; - mutexes.push_back(mux); - } + literal_vector mux; + for (literal lit : c) + if (slits.contains(~lit)) + mux.push_back(~lit); + + if (mux.size() <= 1) + continue; + + for (literal m : mux) + slits.remove(m); + + change = true; + mutexes.push_back(mux); } - if (!change) return; + if (!change) + return; lits.reset(); - for (literal l : slits) { + for (literal l : slits) lits.push_back(l); - } } void solver::display(std::ostream& out, ineq const& ineq, bool values) const { From f3fc6a50f317656314f0064b2a15c7de530550db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 11:57:42 -0800 Subject: [PATCH 014/258] formatting --- src/tactic/arith/lia2card_tactic.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 5f6edf6ea..97c6f466f 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -216,11 +216,10 @@ public: } // IF_VERBOSE(0, verbose_stream() << mk_pp(g->form(i), m) << "\n--->\n" << new_curr << "\n";); g->update(i, new_curr, new_pr, g->dep(i)); - } - for (expr* a : axioms) { + for (expr* a : axioms) g->assert_expr(a); - } + if (m_mc) g->add(m_mc.get()); g->inc_depth(); result.push_back(g.get()); From 7ddfc542502937409665dc83c8a6027a04eb6353 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 11:58:02 -0800 Subject: [PATCH 015/258] shortcut negation --- src/sat/smt/atom2bool_var.cpp | 3 ++- src/sat/tactic/sat2goal.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/atom2bool_var.cpp b/src/sat/smt/atom2bool_var.cpp index 65c91ed79..996e8e5e9 100644 --- a/src/sat/smt/atom2bool_var.cpp +++ b/src/sat/smt/atom2bool_var.cpp @@ -19,6 +19,7 @@ Notes: #include "util/ref_util.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_util.h" #include "tactic/goal.h" #include "sat/smt/atom2bool_var.h" @@ -27,7 +28,7 @@ void atom2bool_var::mk_inv(expr_ref_vector & lit2expr) const { sat::literal l(static_cast(kv.m_value), false); lit2expr.set(l.index(), kv.m_key); l.neg(); - lit2expr.set(l.index(), m().mk_not(kv.m_key)); + lit2expr.set(l.index(), mk_not(m(), kv.m_key)); } } diff --git a/src/sat/tactic/sat2goal.cpp b/src/sat/tactic/sat2goal.cpp index 482e441ef..7614857cb 100644 --- a/src/sat/tactic/sat2goal.cpp +++ b/src/sat/tactic/sat2goal.cpp @@ -218,7 +218,7 @@ struct sat2goal::imp { } sat::literal lit(l.var(), false); m_lit2expr.set(lit.index(), aux); - m_lit2expr.set((~lit).index(), m.mk_not(aux)); + m_lit2expr.set((~lit).index(), mk_not(m, aux)); } return m_lit2expr.get(l.index()); } From 4392b8871850ac797ed676f620f8798e903993fa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 12:00:00 -0800 Subject: [PATCH 016/258] return negated literal when expression is "not" --- src/sat/tactic/goal2sat.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 30d73a21a..faaee95f8 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -805,6 +805,7 @@ struct goal2sat::imp : public sat::sat_internalizer { } sat::literal internalize(expr* n, bool redundant) override { + bool is_not = m.is_not(n, n); flet _top(m_top_level, false); unsigned sz = m_result_stack.size(); (void)sz; @@ -820,6 +821,9 @@ struct goal2sat::imp : public sat::sat_internalizer { m_map.insert(n, result.var()); m_solver.set_external(result.var()); } + + if (is_not) + result.neg(); return result; } From 1e0d49512ba480a4135302c2988e9089d330cfd6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 12:00:16 -0800 Subject: [PATCH 017/258] call mux finder --- src/sat/sat_solver.cpp | 4 ++-- src/sat/sat_solver.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 90e31b97a..4d4c2d132 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4174,7 +4174,7 @@ namespace sat { lbool solver::find_mutexes(literal_vector const& lits, vector & mutexes) { max_cliques mc; m_user_bin_clauses.reset(); - m_binary_clause_graph.reset(); + // m_binary_clause_graph.reset(); collect_bin_clauses(m_user_bin_clauses, true, false); hashtable, default_eq > seen_bc; for (auto const& b : m_user_bin_clauses) { @@ -4189,7 +4189,7 @@ namespace sat { vector _mutexes; literal_vector _lits(lits); if (m_ext) { - // m_ext->find_mutexes(_lits, mutexes); + m_ext->find_mutexes(_lits, mutexes); } unsigned_vector ps; for (literal lit : _lits) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 74bb182e8..98fd32591 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -755,7 +755,7 @@ namespace sat { u_map m_antecedents; literal_vector m_todo_antecedents; - vector m_binary_clause_graph; + // vector m_binary_clause_graph; bool extract_assumptions(literal lit, index_set& s); From 994c7ef52dcedd245498eb707a6ff3fdb01358cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 12:00:26 -0800 Subject: [PATCH 018/258] format --- src/opt/opt_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index a8c0d5144..3551686f7 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -301,7 +301,7 @@ namespace opt { IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n"); - lbool is_sat = s.check_sat(asms.size(),asms.data()); + lbool is_sat = s.check_sat(asms.size(), asms.data()); TRACE("opt", s.display(tout << "initial search result: " << is_sat << "\n");); if (is_sat != l_false) { From 6a412f7f043690d0032a1c6cf742bdd1692df7d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jan 2022 12:00:54 -0800 Subject: [PATCH 019/258] allow to pass Booleans as arguments to arithmetic expressions --- src/ast/ast.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 6ef012836..2472e9efd 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -27,6 +27,7 @@ Revision History: #include "ast/ast_util.h" #include "ast/ast_smt2_pp.h" #include "ast/array_decl_plugin.h" +#include "ast/arith_decl_plugin.h" #include "ast/ast_translation.h" #include "util/z3_version.h" @@ -2131,12 +2132,17 @@ bool ast_manager::coercion_needed(func_decl * decl, unsigned num_args, expr * co expr* ast_manager::coerce_to(expr* e, sort* s) { sort* se = e->get_sort(); if (s != se && s->get_family_id() == arith_family_id && se->get_family_id() == arith_family_id) { - if (s->get_decl_kind() == REAL_SORT) { + if (s->get_decl_kind() == REAL_SORT) return mk_app(arith_family_id, OP_TO_REAL, e); - } - else { - return mk_app(arith_family_id, OP_TO_INT, e); - } + else + return mk_app(arith_family_id, OP_TO_INT, e); + } + if (s != se && s->get_family_id() == arith_family_id && is_bool(e)) { + arith_util au(*this); + if (s->get_decl_kind() == REAL_SORT) + return mk_ite(e, au.mk_real(1), au.mk_real(0)); + else + return mk_ite(e, au.mk_int(1), au.mk_int(0)); } else { return e; From 05e28e43441c45356b70d5b9b0d117856744f1b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Feb 2022 13:08:43 -0800 Subject: [PATCH 020/258] fix #5812 --- src/smt/theory_array.h | 2 +- src/smt/theory_array_full.cpp | 47 +++++++++++++++++++++++++++++------ src/smt/theory_array_full.h | 4 +++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_array.h b/src/smt/theory_array.h index 67ae8a8a5..46922e049 100644 --- a/src/smt/theory_array.h +++ b/src/smt/theory_array.h @@ -28,7 +28,7 @@ namespace smt { unsigned m_num_axiom1, m_num_axiom2a, m_num_axiom2b, m_num_extensionality, m_num_eq_splits; unsigned m_num_map_axiom, m_num_default_map_axiom; unsigned m_num_select_const_axiom, m_num_default_store_axiom, m_num_default_const_axiom, m_num_default_as_array_axiom; - unsigned m_num_select_as_array_axiom; + unsigned m_num_select_as_array_axiom, m_num_default_lambda_axiom; void reset() { memset(this, 0, sizeof(theory_array_stats)); } theory_array_stats() { reset(); } }; diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 6e7403737..1dd607f59 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -181,6 +181,17 @@ namespace smt { } } + void theory_array_full::add_lambda(theory_var v, enode* lam) { + var_data * d = m_var_data[v]; + unsigned lambda_equiv_class_size = get_lambda_equiv_size(v, d); + if (m_params.m_array_always_prop_upward || lambda_equiv_class_size >= 1) + set_prop_upward(v, d); + ptr_vector & lambdas = m_var_data_full[v]->m_lambdas; + m_trail_stack.push(push_back_trail(lambdas)); + lambdas.push_back(lam); + instantiate_default_lambda_def_axiom(lam); + } + void theory_array_full::add_as_array(theory_var v, enode* arr) { var_data * d = m_var_data[v]; unsigned lambda_equiv_class_size = get_lambda_equiv_size(v, d); @@ -238,6 +249,10 @@ namespace smt { instantiate_default_as_array_axiom(n); d->m_as_arrays.push_back(n); } + else if (m.is_lambda_def(n->get_decl())) { + instantiate_default_lambda_def_axiom(n); + d->m_lambdas.push_back(n); + } return r; } @@ -331,18 +346,16 @@ namespace smt { // v1 is the new root SASSERT(v1 == find(v1)); var_data_full * d2 = m_var_data_full[v2]; - for (enode * n : d2->m_maps) { + for (enode * n : d2->m_maps) add_map(v1, n); - } - for (enode * n : d2->m_parent_maps) { + for (enode * n : d2->m_parent_maps) add_parent_map(v1, n); - } - for (enode * n : d2->m_consts) { + for (enode * n : d2->m_consts) add_const(v1, n); - } - for (enode * n : d2->m_as_arrays) { + for (enode * n : d2->m_as_arrays) add_as_array(v1, n); - } + for (enode* n : d2->m_lambdas) + add_lambda(v1, n); TRACE("array", tout << pp(get_enode(v1), m) << "\n"; tout << pp(get_enode(v2), m) << "\n"; @@ -577,6 +590,23 @@ namespace smt { #endif } + bool theory_array_full::instantiate_default_lambda_def_axiom(enode* arr) { + if (!ctx.add_fingerprint(this, m_default_lambda_fingerprint, 1, &arr)) + return false; + m_stats.m_num_default_lambda_axiom++; + expr* def = mk_default(arr->get_expr()); + quantifier* lam = m.is_lambda_def(arr->get_decl()); + expr_ref_vector args(m); + args.push_back(lam); + for (unsigned i = 0; i < lam->get_num_decls(); ++i) + args.push_back(mk_epsilon(lam->get_decl_sort(i)).first); + expr_ref val(mk_select(args), m); + ctx.internalize(def, false); + ctx.internalize(val.get(), false); + return try_assign_eq(val.get(), def); + } + + bool theory_array_full::has_unitary_domain(app* array_term) { SASSERT(is_array_sort(array_term)); sort* s = array_term->get_sort(); @@ -863,5 +893,6 @@ namespace smt { st.update("array def store", m_stats.m_num_default_store_axiom); st.update("array def as-array", m_stats.m_num_default_as_array_axiom); st.update("array sel as-array", m_stats.m_num_select_as_array_axiom); + st.update("array def lambda", m_stats.m_num_default_lambda_axiom); } } diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 19b0e2f6d..09a6daaec 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -28,6 +28,7 @@ namespace smt { ptr_vector m_maps; ptr_vector m_consts; ptr_vector m_as_arrays; + ptr_vector m_lambdas; ptr_vector m_parent_maps; }; @@ -41,6 +42,7 @@ namespace smt { static unsigned const m_default_store_fingerprint = UINT_MAX - 113; static unsigned const m_default_const_fingerprint = UINT_MAX - 115; static unsigned const m_default_as_array_fingerprint = UINT_MAX - 116; + static unsigned const m_default_lambda_fingerprint = UINT_MAX - 117; protected: @@ -66,6 +68,7 @@ namespace smt { void add_map(theory_var v, enode* s); void add_parent_map(theory_var v, enode* s); void add_as_array(theory_var v, enode* arr); + void add_lambda(theory_var v, enode* lam); void add_parent_select(theory_var v, enode * s) override; void add_parent_default(theory_var v); @@ -76,6 +79,7 @@ namespace smt { bool instantiate_default_store_axiom(enode* store); bool instantiate_default_map_axiom(enode* map); bool instantiate_default_as_array_axiom(enode* arr); + bool instantiate_default_lambda_def_axiom(enode* arr); bool instantiate_parent_stores_default(theory_var v); bool has_large_domain(app* array_term); From 9d655cc658a2ec857f4fbc0c3d128cbe37b0b919 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Feb 2022 22:07:29 -0800 Subject: [PATCH 021/258] track all unhandled operators instead of latest --- src/smt/theory_lra.cpp | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 42e98e471..66e47bf68 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -65,8 +65,6 @@ class theory_lra::imp { unsigned m_idiv_lim; unsigned m_asserted_qhead; unsigned m_asserted_atoms_lim; - unsigned m_underspecified_lim; - expr* m_not_handled; }; struct delayed_atom { @@ -161,7 +159,7 @@ class theory_lra::imp { svector m_definitions; // asserted rows corresponding to definitions svector m_asserted_atoms; - expr* m_not_handled; + ptr_vector m_not_handled; ptr_vector m_underspecified; ptr_vector m_idiv_terms; vector > m_use_list; // bounds where variables are used. @@ -299,14 +297,15 @@ class theory_lra::imp { } void found_unsupported(expr* n) { - ctx().push_trail(value_trail(m_not_handled)); - TRACE("arith", tout << "unsupported " << mk_pp(n, m) << "\n";); - m_not_handled = n; - } + ctx().push_trail(push_back_vector>(m_not_handled)); + TRACE("arith", tout << "unsupported " << mk_pp(n, m) << "\n"); + m_not_handled.push_back(n); + } void found_underspecified(expr* n) { if (a.is_underspecified(n)) { TRACE("arith", tout << "Unhandled: " << mk_pp(n, m) << "\n";); + ctx().push_trail(push_back_vector>(m_underspecified)); m_underspecified.push_back(to_app(n)); } expr* e = nullptr, *x = nullptr, *y = nullptr; @@ -857,7 +856,6 @@ public: m_zero_var(UINT_MAX), m_rone_var(UINT_MAX), m_rzero_var(UINT_MAX), - m_not_handled(nullptr), m_asserted_qhead(0), m_assume_eq_head(0), m_num_conflicts(0), @@ -1052,8 +1050,6 @@ public: sc.m_asserted_qhead = m_asserted_qhead; sc.m_idiv_lim = m_idiv_terms.size(); sc.m_asserted_atoms_lim = m_asserted_atoms.size(); - sc.m_not_handled = m_not_handled; - sc.m_underspecified_lim = m_underspecified.size(); lp().push(); if (m_nla) m_nla->push(); @@ -1070,8 +1066,6 @@ public: m_idiv_terms.shrink(m_scopes[old_size].m_idiv_lim); m_asserted_atoms.shrink(m_scopes[old_size].m_asserted_atoms_lim); m_asserted_qhead = m_scopes[old_size].m_asserted_qhead; - m_underspecified.shrink(m_scopes[old_size].m_underspecified_lim); - m_not_handled = m_scopes[old_size].m_not_handled; m_scopes.resize(old_size); lp().pop(num_scopes); // VERIFY(l_false != make_feasible()); @@ -1567,9 +1561,9 @@ public: if (assume_eqs()) { ++m_stats.m_assume_eqs; return FC_CONTINUE; - } - if (m_not_handled != nullptr) { - TRACE("arith", tout << "unhandled operator " << mk_pp(m_not_handled, m) << "\n";); + } + for (expr* e : m_not_handled) { + TRACE("arith", tout << "unhandled operator " << mk_pp(e, m) << "\n";); st = FC_GIVEUP; } return st; @@ -2020,9 +2014,8 @@ public: Use the set to determine if a variable is shared. */ bool is_shared(theory_var v) const { - if (m_underspecified.empty()) { + if (m_underspecified.empty()) return false; - } enode * n = get_enode(v); enode * r = n->get_root(); unsigned usz = m_underspecified.size(); @@ -2031,19 +2024,15 @@ public: for (unsigned i = 0; i < usz; ++i) { app* u = m_underspecified[i]; unsigned sz = u->get_num_args(); - for (unsigned j = 0; j < sz; ++j) { - if (ctx().get_enode(u->get_arg(j))->get_root() == r) { + for (unsigned j = 0; j < sz; ++j) + if (ctx().get_enode(u->get_arg(j))->get_root() == r) return true; - } - } } } else { - for (enode * parent : r->get_const_parents()) { - if (a.is_underspecified(parent->get_expr())) { + for (enode * parent : r->get_const_parents()) + if (a.is_underspecified(parent->get_expr())) return true; - } - } } return false; } @@ -3199,7 +3188,7 @@ public: m_arith_eq_adapter.reset_eh(); m_solver = nullptr; m_internalize_head = 0; - m_not_handled = nullptr; + m_not_handled.reset(); del_bounds(0); m_unassigned_bounds.reset(); m_asserted_qhead = 0; From e9dad84b857c10c710605cc5294349737d4dcbfe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Feb 2022 03:35:32 +0200 Subject: [PATCH 022/258] update documentation comments --- src/api/z3_api.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0b0d286d1..c9bf68a67 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6672,6 +6672,13 @@ extern "C" { /** \brief register a user-properator with the solver. + + \param c - context. + \param s - solver object. + \param user_context - a context used to maintain state for callbacks. + \param push_eh - a callback invoked when scopes are pushed + \param pop_eh - a callback invoked when scopes are poped + \param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers. */ void Z3_API Z3_solver_propagate_init( @@ -6694,11 +6701,15 @@ extern "C" { /** \brief register a callback on final check. This provides freedom to the propagator to delay actions or implement a branch-and bound solver. + The final check is invoked when all decision variables have been assigned by the solver. - The final_eh callback takes as argument the original user_context that was used - when calling \c Z3_solver_propagate_init, and it takes a callback context for propagations. - If may use the callback context to invoke the \c Z3_solver_propagate_consequence function. - If the callback context gets used, the solver continues. + The \c final_eh callback takes as argument the original user_context that was used + when calling \c Z3_solver_propagate_init, and it takes a callback context with the + opaque type \c Z3_solver_callback. + The callback context is passed as argument to invoke the \c Z3_solver_propagate_consequence function. + The callback context can only be accessed (for propagation and for dynamically registering expressions) within a callback. + If the callback context gets used for propagation or conflicts, those propagations take effect and + may trigger new decision variables to be set. */ void Z3_API Z3_solver_propagate_final(Z3_context c, Z3_solver s, Z3_final_eh final_eh); From 8a84cacfea8b47bdbc2e3be41aaee6c61a082fbf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Feb 2022 04:02:12 +0200 Subject: [PATCH 023/258] add tuple support for __getitem__ #5815 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 13c922f85..5559f708e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2015,8 +2015,7 @@ class QuantifierRef(BoolRef): """ if z3_debug(): _z3_assert(self.is_lambda(), "quantifier should be a lambda expression") - arg = self.sort().domain().cast(arg) - return _to_expr_ref(Z3_mk_select(self.ctx_ref(), self.as_ast(), arg.as_ast()), self.ctx) + return _array_select(self, arg) def weight(self): """Return the weight annotation of `self`. @@ -4546,13 +4545,21 @@ class ArrayRef(ExprRef): >>> a[i].sexpr() '(select a i)' """ - arg = self.domain().cast(arg) - return _to_expr_ref(Z3_mk_select(self.ctx_ref(), self.as_ast(), arg.as_ast()), self.ctx) + return _array_select(self, arg) def default(self): return _to_expr_ref(Z3_mk_array_default(self.ctx_ref(), self.as_ast()), self.ctx) +def _array_select(ar, arg): + if isinstance(arg, tuple): + args = [ar.domain().cast(a) for a in arg] + _args, sz = _to_ast_array(args) + return _to_expr_ref(Z3_mk_select_n(ar.ctx_ref(), ar.as_ast(), sz, _args), ar.ctx) + arg = ar.domain().cast(arg) + return _to_expr_ref(Z3_mk_select(ar.ctx_ref(), ar.as_ast(), arg.as_ast()), ar.ctx) + + def is_array_sort(a): return Z3_get_sort_kind(a.ctx.ref(), Z3_get_sort(a.ctx.ref(), a.ast)) == Z3_ARRAY_SORT From 1c10ce4070a29679244f7cc57fa1087d6a1d5cac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Feb 2022 08:40:56 +0200 Subject: [PATCH 024/258] #5815 - surface multi-arity arrays over python API --- src/api/api_array.cpp | 16 ++++++++++++++++ src/api/python/z3/z3.py | 42 ++++++++++++++++++++++++++++++----------- src/api/z3_api.h | 16 ++++++++++++++++ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index c1ea4729e..7aa3a87bf 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -309,6 +309,22 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + Z3_sort Z3_API Z3_get_array_sort_domain_n(Z3_context c, Z3_sort t, unsigned idx) { + Z3_TRY; + LOG_Z3_get_array_sort_domain_n(c, t, idx); + RESET_ERROR_CODE(); + CHECK_VALID_AST(t, nullptr); + if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && + to_sort(t)->get_decl_kind() == ARRAY_SORT && + get_array_arity(to_sort(t)) > idx) { + Z3_sort r = reinterpret_cast(get_array_domain(to_sort(t), idx)); + RETURN_Z3(r); + } + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + RETURN_Z3(nullptr); + Z3_CATCH_RETURN(nullptr); + } + Z3_sort Z3_API Z3_get_array_sort_range(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_array_sort_range(c, t); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 5559f708e..2f7d33f4e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4495,6 +4495,11 @@ class ArraySortRef(SortRef): """ return _to_sort_ref(Z3_get_array_sort_domain(self.ctx_ref(), self.ast), self.ctx) + def domain_n(self, i): + """Return the domain of the array sort `self`. + """ + return _to_sort_ref(Z3_get_array_sort_domain_n(self.ctx_ref(), self.ast, i), self.ctx) + def range(self): """Return the range of the array sort `self`. @@ -4526,6 +4531,10 @@ class ArrayRef(ExprRef): """ return self.sort().domain() + def domain_n(self, i): + """Shorthand for self.sort().domain_n(i)`.""" + return self.sort().domain_n(i) + def range(self): """Shorthand for `self.sort().range()`. @@ -4553,7 +4562,7 @@ class ArrayRef(ExprRef): def _array_select(ar, arg): if isinstance(arg, tuple): - args = [ar.domain().cast(a) for a in arg] + args = [ar.domain_n(i).cast(arg[i]) for i in range(len(arg))] _args, sz = _to_ast_array(args) return _to_expr_ref(Z3_mk_select_n(ar.ctx_ref(), ar.as_ast(), sz, _args), ar.ctx) arg = ar.domain().cast(arg) @@ -4686,7 +4695,7 @@ def ArraySort(*sig): return ArraySortRef(Z3_mk_array_sort_n(ctx.ref(), arity, dom, r.ast), ctx) -def Array(name, dom, rng): +def Array(name, *sorts): """Return an array constant named `name` with the given domain and range sorts. >>> a = Array('a', IntSort(), IntSort()) @@ -4695,12 +4704,12 @@ def Array(name, dom, rng): >>> a[0] a[0] """ - s = ArraySort(dom, rng) + s = ArraySort(sorts) ctx = s.ctx return ArrayRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), s.ast), ctx) -def Update(a, i, v): +def Update(a, *args): """Return a Z3 store array expression. >>> a = Array('a', IntSort(), IntSort()) @@ -4716,10 +4725,20 @@ def Update(a, i, v): """ if z3_debug(): _z3_assert(is_array_sort(a), "First argument must be a Z3 array expression") - i = a.sort().domain().cast(i) - v = a.sort().range().cast(v) + args = _get_args(args) ctx = a.ctx - return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx) + if len(args) <= 1: + raise Z3Exception("array update requires index and value arguments") + if len(args) == 2: + i = args[0] + v = args[1] + i = a.sort().domain().cast(i) + v = a.sort().range().cast(v) + return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx) + v = a.sort().range().cast(args[-1]) + idxs = [a.sort().domain_n(i).cast(args[i]) for i in range(len(args)-1)] + _args, sz = _to_ast_array(idxs) + return _to_expr_ref(Z3_mk_store_n(ctx.ref(), a.as_ast(), sz, _args, v.as_ast()), ctx) def Default(a): @@ -4733,7 +4752,7 @@ def Default(a): return a.default() -def Store(a, i, v): +def Store(a, *args): """Return a Z3 store array expression. >>> a = Array('a', IntSort(), IntSort()) @@ -4747,10 +4766,10 @@ def Store(a, i, v): >>> prove(Implies(i != j, s[j] == a[j])) proved """ - return Update(a, i, v) + return Update(a, args) -def Select(a, i): +def Select(a, *args): """Return a Z3 select array expression. >>> a = Array('a', IntSort(), IntSort()) @@ -4760,9 +4779,10 @@ def Select(a, i): >>> eq(Select(a, i), a[i]) True """ + args = _get_args(args) if z3_debug(): _z3_assert(is_array_sort(a), "First argument must be a Z3 array expression") - return a[i] + return a[args] def Map(f, *args): diff --git a/src/api/z3_api.h b/src/api/z3_api.h index c9bf68a67..16d3a292c 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4358,11 +4358,27 @@ extern "C" { \sa Z3_mk_array_sort \sa Z3_get_sort_kind + \sa Z3_get_array_sort_domain_n def_API('Z3_get_array_sort_domain', SORT, (_in(CONTEXT), _in(SORT))) */ Z3_sort Z3_API Z3_get_array_sort_domain(Z3_context c, Z3_sort t); + + /** + \brief Return the i'th domain sort of an n-dimensional array. + + \pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT + + \sa Z3_mk_array_sort + \sa Z3_get_sort_kind + \sa Z3_get_array_sort_domain + + def_API('Z3_get_array_sort_domain_n', SORT, (_in(CONTEXT), _in(SORT), _in(UINT))) + + */ + Z3_sort Z3_API Z3_get_array_sort_domain_n(Z3_context c, Z3_sort t, unsigned idx); + /** \brief Return the range of the given array sort. From 03ff3201b90a3aef32c99e9e2d367e7c44260e82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Feb 2022 08:57:58 +0200 Subject: [PATCH 025/258] block recursive definitions with lambdas until they are properly supported #5813 --- src/ast/recfun_decl_plugin.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 9a8c59ae9..0e9c27655 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -225,6 +225,11 @@ namespace recfun { m_vars.append(n_vars, vars); m_rhs = rhs; + if (!is_macro) + for (expr* e : subterms::all(m_rhs)) + if (is_lambda(e)) + throw default_exception("recursive definitions with lambdas are not supported"); + expr_ref_vector conditions(m); // is the function a macro (unconditional body)? @@ -233,6 +238,8 @@ namespace recfun { add_case(name, 0, conditions, rhs); return; } + + // analyze control flow of `rhs`, accumulating guards and // rebuilding a `ite`-free RHS on the fly for each path in `rhs`. From d4ea67a6e714914a5ce29790a260d5809d5ff91a Mon Sep 17 00:00:00 2001 From: Kaleb Crans <69497802+kcrans@users.noreply.github.com> Date: Sun, 6 Feb 2022 09:47:47 -0800 Subject: [PATCH 026/258] Fix a few typos in README (#5782) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 643e49823..17d59558e 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ A 32 bit build should work similarly (but is untested); the same is true for 32/ By default, it will install z3 executable at ``PREFIX/bin``, libraries at ``PREFIX/lib``, and include files at ``PREFIX/include``, where ``PREFIX`` -installation prefix if inferred by the ``mk_make.py`` script. It is usually +installation prefix is inferred by the ``mk_make.py`` script. It is usually ``/usr`` for most Linux distros, and ``/usr/local`` for FreeBSD and macOS. Use the ``--prefix=`` command line option to change the install prefix. For example: @@ -158,7 +158,7 @@ You can install the Python wrapper for Z3 for the latest release from pypi using Use the ``--python`` command line flag with ``mk_make.py`` to enable building these. -Note that is required on certain platforms that the Python package directory +Note that it is required on certain platforms that the Python package directory (``site-packages`` on most distributions and ``dist-packages`` on Debian based distributions) live under the install prefix. If you use a non standard prefix you can use the ``--pypkgdir`` option to change the Python package directory From 3f3d05856787dd6a6ae030a81800381c310a5969 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 7 Feb 2022 06:15:49 +0200 Subject: [PATCH 027/258] extract also units from search state --- src/smt/smt_context.cpp | 16 ++++++++++++++++ src/smt/smt_context.h | 2 ++ src/smt/smt_kernel.cpp | 6 +++++- src/smt/smt_kernel.h | 6 ++++++ src/smt/smt_solver.cpp | 4 ++++ src/solver/solver.cpp | 1 + src/solver/solver.h | 2 ++ 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 60eccf962..735da24eb 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4613,6 +4613,22 @@ namespace smt { return result; } + void context::get_units(expr_ref_vector& result) { + expr_mark visited; + for (expr* fml : result) + visited.mark(fml); + for (literal lit : m_assigned_literals) { + if (get_assign_level(lit) > m_base_lvl) + break; + expr_ref e(m); + literal2expr(lit, e); + if (visited.is_marked(e)) + continue; + result.push_back(std::move(e)); + } + } + + failure context::get_last_search_failure() const { return m_last_search_failure; } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 89b94412d..b8c8a7ee9 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1691,6 +1691,8 @@ namespace smt { void get_assertions(ptr_vector & result) { m_asserted_formulas.get_assertions(result); } + void get_units(expr_ref_vector& result); + /* * user-propagator */ diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 4a2c8bae9..347260c84 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -177,6 +177,10 @@ namespace smt { void kernel::get_assignments(expr_ref_vector & result) { m_imp->m_kernel.get_assignments(result); } + + void kernel::get_units(expr_ref_vector & result) { + m_imp->m_kernel.get_units(result); + } void kernel::get_relevant_labels(expr * cnstr, buffer & result) { m_imp->m_kernel.get_relevant_labels(cnstr, result); @@ -280,4 +284,4 @@ namespace smt { m_imp->m_kernel.user_propagate_register_created(r); } -}; \ No newline at end of file +}; diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 681bdd55b..28680e7a6 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -202,6 +202,12 @@ namespace smt { \brief Return the set of formulas assigned by the kernel. */ void get_assignments(expr_ref_vector & result); + + + /** + \brief Return units assigned by the kernel. + */ + void get_units(expr_ref_vector& result); /** \brief Return the set of relevant labels in the last check command. diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 03f55585a..1cb9b26e1 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -318,6 +318,10 @@ namespace { return m_context.get_formula(idx); } + void get_units_core(expr_ref_vector& units) override { + m_context.get_units(units); + } + expr_ref_vector cube(expr_ref_vector& vars, unsigned cutoff) override { ast_manager& m = get_manager(); if (!m_cuber) { diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 7dcca2ecc..d14648058 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -242,6 +242,7 @@ expr_ref_vector solver::get_units() { ast_manager& m = get_manager(); expr_ref_vector fmls(m), result(m), tmp(m); get_assertions(fmls); + get_units_core(fmls); obj_map units; for (expr* f : fmls) { if (m.is_not(f, f) && is_literal(m, f)) { diff --git a/src/solver/solver.h b/src/solver/solver.h index 090cd9d9b..13692c857 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -261,6 +261,8 @@ public: */ expr_ref_vector get_units(); + virtual void get_units_core(expr_ref_vector& units) {} + expr_ref_vector get_non_units(); virtual expr_ref_vector get_trail() = 0; // { return expr_ref_vector(get_manager()); } From 9958cab5cc737edf443340e5e08c094d91fc0c93 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 7 Feb 2022 07:43:30 +0200 Subject: [PATCH 028/258] fix #5808 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 8cef18ab2..ef0fdfedd 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1881,10 +1881,9 @@ namespace smt { inc_coeff(conseq, offset); clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); - if (cjs && !is_proof_justification(*cjs)) { - TRACE("pb", tout << "skipping justification for clause over: " << conseq << " " - << typeid(*cjs).name() << "\n";); - break; + if (cjs && !is_proof_justification(*cjs)) { + TRACE("pb", tout << "not processing justification over: " << conseq << " " << typeid(*cjs).name() << "\n";); + return false; } unsigned num_lits = cls.get_num_literals(); if (cls.get_literal(0) == conseq) { From 0059e880365518bd2d9938927b17079aa47a8c9a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 7 Feb 2022 20:10:32 +0200 Subject: [PATCH 029/258] fix #5808 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index ef0fdfedd..0dc52c1b2 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1881,11 +1881,13 @@ namespace smt { inc_coeff(conseq, offset); clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); - if (cjs && !is_proof_justification(*cjs)) { - TRACE("pb", tout << "not processing justification over: " << conseq << " " << typeid(*cjs).name() << "\n";); - return false; - } unsigned num_lits = cls.get_num_literals(); + if (cjs && typeid(smt::unit_resolution_justification) == typeid(*cjs)) + ; + else if (cjs && !is_proof_justification(*cjs)) { + TRACE("pb", tout << "not processing justification over: " << conseq << " " << typeid(*cjs).name() << "\n";); + break; + } if (cls.get_literal(0) == conseq) { process_antecedent(cls.get_literal(1), offset); } From 4f6fcf8ea78492e1d90398bcd3a663f8517f2a66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Feb 2022 10:20:19 +0200 Subject: [PATCH 030/258] fix #5814 Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 042e6af46..1e105b002 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1995,7 +1995,7 @@ class MLComponent(Component): LIBZ3 = LIBZ3 + ' ' + ' '.join(map(lambda x: '-cclib ' + x, LDFLAGS.split())) - stubs_install_path = '$$(%s printconf path)/stublibs' % OCAMLFIND + stubs_install_path = '$$(%s printconf destdir)/stublibs' % OCAMLFIND if not STATIC_LIB: loadpath = '-ccopt -L' + stubs_install_path dllpath = '-dllpath ' + stubs_install_path From 07d02ea41578819dcd58b623fa979914a4dc4809 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 Feb 2022 12:08:36 +0200 Subject: [PATCH 031/258] fix #5829 --- src/api/python/z3/z3.py | 8 ++++---- src/ast/pb_decl_plugin.cpp | 9 +++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 2f7d33f4e..34d586a93 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8883,7 +8883,7 @@ def _pb_args_coeffs(args, default_ctx=None): for i in range(len(coeffs)): _z3_check_cint_overflow(coeffs[i], "coefficient") _coeffs[i] = coeffs[i] - return ctx, sz, _args, _coeffs + return ctx, sz, _args, _coeffs, args def PbLe(args, k): @@ -8893,7 +8893,7 @@ def PbLe(args, k): >>> f = PbLe(((a,1),(b,3),(c,2)), 3) """ _z3_check_cint_overflow(k, "k") - ctx, sz, _args, _coeffs = _pb_args_coeffs(args) + ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args) return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx) @@ -8904,7 +8904,7 @@ def PbGe(args, k): >>> f = PbGe(((a,1),(b,3),(c,2)), 3) """ _z3_check_cint_overflow(k, "k") - ctx, sz, _args, _coeffs = _pb_args_coeffs(args) + ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args) return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx) @@ -8915,7 +8915,7 @@ def PbEq(args, k, ctx=None): >>> f = PbEq(((a,1),(b,3),(c,2)), 3) """ _z3_check_cint_overflow(k, "k") - ctx, sz, _args, _coeffs = _pb_args_coeffs(args) + ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args) return BoolRef(Z3_mk_pbeq(ctx.ref(), sz, _args, _coeffs, k), ctx) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 71722c7d0..f46f1657c 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -33,11 +33,9 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p unsigned arity, sort * const * domain, sort * range) { SASSERT(m_manager); ast_manager& m = *m_manager; - for (unsigned i = 0; i < arity; ++i) { - if (!m.is_bool(domain[i])) { + for (unsigned i = 0; i < arity; ++i) + if (!m.is_bool(domain[i])) m.raise_exception("invalid non-Boolean sort applied to 'at-most'"); - } - } symbol sym; switch(k) { case OP_AT_LEAST_K: sym = m_at_least_sym; break; @@ -50,9 +48,8 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p switch(k) { case OP_AT_LEAST_K: case OP_AT_MOST_K: { - if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) { + if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) m.raise_exception("function expects one non-negative integer parameter"); - } func_decl_info info(m_family_id, k, 1, parameters); return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info); } From 81e94b21541280cb7fbc3426419ed6c3a8f24dd4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 Feb 2022 12:10:01 +0200 Subject: [PATCH 032/258] na Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index f46f1657c..d4797b507 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -35,7 +35,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p ast_manager& m = *m_manager; for (unsigned i = 0; i < arity; ++i) if (!m.is_bool(domain[i])) - m.raise_exception("invalid non-Boolean sort applied to 'at-most'"); + m.raise_exception("invalid non-Boolean sort applied to Pseudo-Boolean relation"); symbol sym; switch(k) { case OP_AT_LEAST_K: sym = m_at_least_sym; break; From d745d03afdfdf638d66093e2bfbacaf87187f35b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Feb 2022 08:55:43 +0200 Subject: [PATCH 033/258] switch to vs 2022 Signed-off-by: Nikolaj Bjorner --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bff70c859..d29a3dd51 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -217,12 +217,12 @@ jobs: $(setupCmd1) $(setupCmd2) $(setupCmd3) - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch) + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch) cmake $(bindings) -G "NMake Makefiles" ../ nmake cd .. - script: | - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch) + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch) pushd build\python python z3test.py z3 python z3test.py z3num From 3d26b501e78466f49abb889077d4e8f0d8e6b5f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Feb 2022 10:31:04 +0200 Subject: [PATCH 034/258] fix #5827 #5828 --- src/ast/rewriter/func_decl_replace.cpp | 3 ++- src/smt/smt_internalizer.cpp | 1 - src/smt/theory_datatype.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/func_decl_replace.cpp b/src/ast/rewriter/func_decl_replace.cpp index 512a831af..022afc538 100644 --- a/src/ast/rewriter/func_decl_replace.cpp +++ b/src/ast/rewriter/func_decl_replace.cpp @@ -23,7 +23,8 @@ Revision History: expr_ref func_decl_replace::operator()(expr* e) { m_todo.push_back(e); - + m_refs.push_back(e); + while (!m_todo.empty()) { expr* a = m_todo.back(), *b; if (m_cache.contains(a)) { diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 525d0075e..fd55d5fd0 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -375,7 +375,6 @@ namespace smt { } else { SASSERT(is_app(n)); - SASSERT(!gate_ctx); internalize_term(to_app(n)); } } diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 765513823..1aa8bbea3 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -297,7 +297,7 @@ namespace smt { TRACE("datatype", tout << "internalizing term:\n" << mk_pp(term, m) << "\n";); unsigned num_args = term->get_num_args(); for (unsigned i = 0; i < num_args; i++) - ctx.internalize(term->get_arg(i), has_quantifiers(term)); + ctx.internalize(term->get_arg(i), m.is_bool(term) && has_quantifiers(term)); // the internalization of the arguments may trigger the internalization of term. if (ctx.e_internalized(term)) return true; From 9a4d6cee6c9e7626f0c72f349d6c2b5b30df6551 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Feb 2022 19:36:14 +0200 Subject: [PATCH 035/258] overhead with push-ite on shared terms --- src/ast/rewriter/poly_rewriter_def.h | 3 +-- src/ast/rewriter/th_rewriter.cpp | 10 ++++++---- src/tactic/tactic.cpp | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index b9ac64749..eb72ddd67 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -979,9 +979,8 @@ expr* poly_rewriter::merge_muls(expr* x, expr* y) { template bool poly_rewriter::hoist_ite(expr_ref& e) { - if (!m_hoist_ite) { + if (!m_hoist_ite) return false; - } obj_hashtable shared; ptr_buffer adds; expr_ref_vector bs(m()), pinned(m()); diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 2aaf4626c..bb29b53db 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -295,6 +295,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg { bool is_ite_value_tree(expr * t) { if (!m().is_ite(t)) return false; + if (t->get_ref_count() != 1) + return false; ptr_buffer todo; todo.push_back(to_app(t)); while (!todo.empty()) { @@ -319,7 +321,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { br_status pull_ite(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { if (num == 2 && m().is_bool(f->get_range()) && !m().is_bool(args[0])) { if (m().is_ite(args[0])) { - if (m().is_value(args[1])) + if (m().is_value(args[1]) && args[0]->get_ref_count() == 1) return pull_ite_core(f, to_app(args[0]), to_app(args[1]), result); if (m().is_ite(args[1]) && to_app(args[0])->get_arg(0) == to_app(args[1])->get_arg(0)) { // (p (ite C A1 B1) (ite C A2 B2)) --> (ite (p A1 A2) (p B1 B2)) @@ -329,17 +331,17 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return BR_REWRITE2; } } - if (m().is_ite(args[1]) && m().is_value(args[0])) + if (m().is_ite(args[1]) && m().is_value(args[0]) && args[1]->get_ref_count() == 1) return pull_ite_core(f, to_app(args[1]), to_app(args[0]), result); } family_id fid = f->get_family_id(); if (num == 2 && (fid == m().get_basic_family_id() || fid == m_a_rw.get_fid() || fid == m_bv_rw.get_fid())) { // (f v3 (ite c v1 v2)) --> (ite v (f v3 v1) (f v3 v2)) - if (m().is_value(args[0]) && is_ite_value_tree(args[1])) + if (m().is_value(args[0]) && is_ite_value_tree(args[1])) return pull_ite_core(f, to_app(args[1]), to_app(args[0]), result); // (f (ite c v1 v2) v3) --> (ite v (f v1 v3) (f v2 v3)) - if (m().is_value(args[1]) && is_ite_value_tree(args[0])) + if (m().is_value(args[1]) && is_ite_value_tree(args[0])) return pull_ite_core(f, to_app(args[0]), to_app(args[1]), result); } return BR_FAILED; diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 575435904..cc0ab8f5e 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -52,6 +52,7 @@ struct tactic_report::imp { << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory << " :after-memory " << std::fixed << std::setprecision(2) << end_memory << ")" << std::endl); + IF_VERBOSE(20, m_goal.display(verbose_stream() << m_id << "\n")); SASSERT(m_goal.is_well_formed()); } }; From aa6ec418e3ac14bffd232ab801aaf07edea20345 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Feb 2022 19:50:49 +0200 Subject: [PATCH 036/258] move idiv test to after cuts/branch Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 66e47bf68..c89628808 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1683,8 +1683,11 @@ public: if (m_idiv_terms.empty()) { return true; } - bool all_divs_valid = true; - for (unsigned i = 0; i < m_idiv_terms.size(); ++i) { + bool all_divs_valid = true; + unsigned count = 0; + unsigned offset = ctx().get_random_value(); + for (unsigned j = 0; j < m_idiv_terms.size(); ++j) { + unsigned i = (offset + j) % m_idiv_terms.size(); expr* n = m_idiv_terms[i]; expr* p = nullptr, *q = nullptr; VERIFY(a.is_idiv(n, p, q)); @@ -1706,6 +1709,7 @@ public: continue; } + if (a.is_numeral(q, r2) && r2.is_pos()) { if (!a.is_bounded(n)) { TRACE("arith", tout << "unbounded " << expr_ref(n, m) << "\n";); @@ -1714,7 +1718,8 @@ public: if (!is_registered_var(v)) continue; lp::impq val_v = get_ivalue(v); - if (val_v.y.is_zero() && val_v.x == div(r1.x, r2)) continue; + if (val_v.y.is_zero() && val_v.x == div(r1.x, r2)) + continue; TRACE("arith", tout << get_value(v) << " != " << r1 << " div " << r2 << "\n";); rational div_r = div(r1.x, r2); @@ -1732,6 +1737,7 @@ public: hi = floor(hi/mul); lo = ceil(lo/mul); } + std::cout << mk_pp(p, m) << " " << mk_pp(n, m) << " " << hi << " " << lo << " " << div_r << "\n"; literal p_le_r1 = mk_literal(a.mk_le(p, a.mk_numeral(hi, true))); literal p_ge_r1 = mk_literal(a.mk_ge(p, a.mk_numeral(lo, true))); literal n_le_div = mk_literal(a.mk_le(n, a.mk_numeral(div_r, true))); @@ -1746,6 +1752,8 @@ public: } all_divs_valid = false; + ++count; + TRACE("arith", tout << r1 << " div " << r2 << "\n"; @@ -1857,9 +1865,6 @@ public: return l_undef; } lbool lia_check = l_undef; - if (!check_idiv_bounds()) { - return l_false; - } switch (m_lia->check(&m_explanation)) { case lp::lia_move::sat: lia_check = l_true; @@ -1929,6 +1934,9 @@ public: default: UNREACHABLE(); } + if (lia_check != l_false && !check_idiv_bounds()) + return l_false; + return lia_check; } From 6202cd5394222e177b60cbe6782d7e6e81b162aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Feb 2022 17:38:19 +0200 Subject: [PATCH 037/258] fix #5842 Signed-off-by: Nikolaj Bjorner --- src/smt/params/smt_params_helper.pyg | 1 - src/smt/params/theory_bv_params.cpp | 2 -- src/smt/theory_bv.cpp | 51 ++++++++++++---------------- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 295b12f80..0eb4cbe9f 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -47,7 +47,6 @@ def_module_params(module_name='smt', ('induction', BOOL, False, 'enable generation of induction lemmas'), ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), - ('bv.eq_axioms', BOOL, True, 'add dynamic equality axioms'), ('bv.watch_diseq', BOOL, False, 'use watch lists instead of eager axioms for bit-vectors'), ('bv.delay', BOOL, True, 'delay internalize expensive bit-vector operations'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index 337af657f..968bf3abb 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -26,7 +26,6 @@ void theory_bv_params::updt_params(params_ref const & _p) { m_hi_div0 = rp.hi_div0(); m_bv_reflect = p.bv_reflect(); m_bv_enable_int2bv2int = p.bv_enable_int2bv(); - m_bv_eq_axioms = p.bv_eq_axioms(); m_bv_delay = p.bv_delay(); } @@ -38,7 +37,6 @@ void theory_bv_params::display(std::ostream & out) const { DISPLAY_PARAM(m_bv_reflect); DISPLAY_PARAM(m_bv_lazy_le); DISPLAY_PARAM(m_bv_cc); - DISPLAY_PARAM(m_bv_eq_axioms); DISPLAY_PARAM(m_bv_blast_max_size); DISPLAY_PARAM(m_bv_enable_int2bv2int); DISPLAY_PARAM(m_bv_delay); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 28ffebb1d..ba0c2933c 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -224,8 +224,6 @@ namespace smt { }; void theory_bv::add_new_diseq_axiom(theory_var v1, theory_var v2, unsigned idx) { - if (!params().m_bv_eq_axioms) - return; m_prop_diseqs.push_back(bv_diseq(v1, v2, idx)); ctx.push_trail(push_back_vector>(m_prop_diseqs)); } @@ -432,8 +430,6 @@ namespace smt { }; void theory_bv::add_fixed_eq(theory_var v1, theory_var v2) { - if (!params().m_bv_eq_axioms) - return; if (v1 > v2) { std::swap(v1, v2); @@ -1152,8 +1148,6 @@ namespace smt { } void theory_bv::expand_diseq(theory_var v1, theory_var v2) { - if (!params().m_bv_eq_axioms) - return; SASSERT(get_bv_size(v1) == get_bv_size(v2)); if (v1 > v2) { @@ -1320,30 +1314,29 @@ namespace smt { } else { ctx.assign(consequent, mk_bit_eq_justification(v1, v2, consequent, antecedent)); - if (params().m_bv_eq_axioms) { - literal_vector lits; - lits.push_back(~consequent); - lits.push_back(antecedent); - literal eq = mk_eq(get_expr(v1), get_expr(v2), false); - lits.push_back(~eq); - // - // Issue #3035: - // merge_eh invokes assign_bit, which updates the propagation queue and includes the - // theory axiom for the propagated equality. When relevancy is non-zero, propagation may get - // lost on backtracking because the propagation queue is reset on conflicts. - // An alternative approach is to ensure the propagation queue is chronological with - // backtracking scopes (ie., it doesn't get reset, but shrunk to a previous level, and similar - // with a qhead indicator. - // - ctx.mark_as_relevant(lits[0]); - ctx.mark_as_relevant(lits[1]); - ctx.mark_as_relevant(lits[2]); - { - scoped_trace_stream _sts(*this, lits); - ctx.mk_th_axiom(get_id(), lits.size(), lits.data()); - } + + literal_vector lits; + lits.push_back(~consequent); + lits.push_back(antecedent); + literal eq = mk_eq(get_expr(v1), get_expr(v2), false); + lits.push_back(~eq); + // + // Issue #3035: + // merge_eh invokes assign_bit, which updates the propagation queue and includes the + // theory axiom for the propagated equality. When relevancy is non-zero, propagation may get + // lost on backtracking because the propagation queue is reset on conflicts. + // An alternative approach is to ensure the propagation queue is chronological with + // backtracking scopes (ie., it doesn't get reset, but shrunk to a previous level, and similar + // with a qhead indicator. + // + ctx.mark_as_relevant(lits[0]); + ctx.mark_as_relevant(lits[1]); + ctx.mark_as_relevant(lits[2]); + { + scoped_trace_stream _sts(*this, lits); + ctx.mk_th_axiom(get_id(), lits.size(), lits.data()); } - + if (m_wpos[v2] == idx) find_wpos(v2); // REMARK: bit_eq_justification is marked as a theory_bv justification. From 33985ebcf5487d04bd9bfc47e18fe737604fdf21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Feb 2022 19:14:54 +0200 Subject: [PATCH 038/258] update expected Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 34d586a93..727f289a1 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1771,7 +1771,7 @@ def Xor(a, b, ctx=None): >>> Xor(p, q) Xor(p, q) >>> simplify(Xor(p, q)) - Not(p) == q + Not(p == q) """ ctx = _get_ctx(_ctx_from_ast_arg_list([a, b], ctx)) s = BoolSort(ctx) From 5bbb8fb8073371fc5b2958c2bd05181ce06a51ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Feb 2022 23:30:12 +0200 Subject: [PATCH 039/258] add bail #5825 --- src/tactic/bv/bit_blaster_model_converter.cpp | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index c389e6df4..061a51220 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -70,7 +70,7 @@ struct bit_blaster_model_converter : public model_converter { bits.insert(to_app(bit)->get_decl()); } } - TRACE("blaster_mc", + TRACE("model_converter", tout << "bits that should not be included in the model:\n"; for (func_decl* f : bits) { tout << f->get_name() << " "; @@ -85,14 +85,14 @@ struct bit_blaster_model_converter : public model_converter { func_decl * f = old_model->get_constant(i); if (bits.contains(f)) continue; - TRACE("blaster_mc", tout << "non-bit: " << f->get_name() << "\n";); + TRACE("model_converter", tout << "non-bit: " << f->get_name() << "\n";); expr * fi = old_model->get_const_interp(f); new_model->register_decl(f, fi); } - TRACE("blaster_mc", tout << "after copy non bits:\n"; model_pp(tout, *new_model);); + TRACE("model_converter", tout << "after copy non bits:\n"; model_pp(tout, *new_model);); new_model->copy_func_interps(*old_model); new_model->copy_usort_interps(*old_model); - TRACE("blaster_mc", tout << "after copying functions and sorts:\n"; model_pp(tout, *new_model);); + TRACE("model_converter", tout << "after copying functions and sorts:\n"; model_pp(tout, *new_model);); } void mk_bvs(model * old_model, model * new_model) { @@ -121,7 +121,9 @@ struct bit_blaster_model_converter : public model_converter { SASSERT(is_uninterp_const(bit)); func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); - if (bit_val != nullptr && m().is_true(bit_val)) + if (bit_val && !m().is_true(bit_val) && !m().is_false(bit_val)) + goto bail; + if (bit_val && m().is_true(bit_val)) val++; } } @@ -136,11 +138,27 @@ struct bit_blaster_model_converter : public model_converter { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); // remark: if old_model does not assign bit_val, then assume it is false. - if (bit_val != nullptr && !util.is_zero(bit_val)) + if (bit_val && !util.is_one(bit_val) && !util.is_zero(bit_val)) + goto bail; + if (bit_val && util.is_one(bit_val)) val++; } } - new_val = util.mk_numeral(val, bv_sz); + new_val = util.mk_numeral(val, bv_sz); + new_model->register_decl(m_vars.get(i), new_val); + continue; + bail: + expr_ref_vector vals(m()); + for (expr* bit : *to_app(bs)) { + func_decl * bit_decl = to_app(bit)->get_decl(); + expr * bit_val = old_model->get_const_interp(bit_decl); + SASSERT(bit_val); + vals.push_back(bit_val); + } + if (TO_BOOL) + new_val = util.mk_bv(vals.size(), vals.data()); + else + new_val = util.mk_concat(vals); new_model->register_decl(m_vars.get(i), new_val); } } From 09da87dc85560312fe5c6dbfa4929e82a420f8e8 Mon Sep 17 00:00:00 2001 From: Valentine Sobol Date: Thu, 17 Feb 2022 00:35:58 +0300 Subject: [PATCH 040/258] use horn_subsume_model_converter in coi filter (#5844) --- src/muz/transforms/dl_mk_coi_filter.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 841ab4637..d3f6555aa 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -139,24 +139,12 @@ namespace datalog { res = nullptr; } if (res && m_context.get_model_converter()) { - generic_model_converter* mc0 = alloc(generic_model_converter, m, "dl_coi"); + horn_subsume_model_converter* mc0 = alloc(horn_subsume_model_converter, m); for (func_decl* f : pruned_preds) { const rule_vector& rules = source.get_predicate_rules(f); - expr_ref_vector fmls(m); for (rule * r : rules) { - app* head = r->get_head(); - expr_ref_vector conj(m); - for (unsigned j = 0; j < head->get_num_args(); ++j) { - expr* arg = head->get_arg(j); - if (!is_var(arg)) { - conj.push_back(m.mk_eq(m.mk_var(j, arg->get_sort()), arg)); - } - } - fmls.push_back(mk_and(conj)); + datalog::del_rule(mc0, *r, false); } - expr_ref fml(m); - fml = m.mk_or(fmls.size(), fmls.data()); - mc0->add(f, fml); } m_context.add_model_converter(mc0); } From 9cf50766a636050da7731bd58dcd01219cbe744b Mon Sep 17 00:00:00 2001 From: Qix Date: Wed, 16 Feb 2022 22:36:34 +0100 Subject: [PATCH 041/258] fix compiler warnings under clang (#5839) --- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/sat/smt/pb_solver.cpp | 2 +- src/smt/theory_lra.cpp | 1 + src/tactic/core/collect_statistics_tactic.cpp | 1 - 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 86de919dc..db1f28743 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -687,7 +687,7 @@ public: return ensure_euf()->user_propagate_register_expr(e); } - void user_propagate_register_created(user_propagator::created_eh_t& r) { + void user_propagate_register_created(user_propagator::created_eh_t& r) override { ensure_euf()->user_propagate_register_created(r); } diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 5e63f19ad..62e3c88fb 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -1458,7 +1458,7 @@ namespace pb { return nullptr; } rational weight(0); - for (auto const [w, l] : wlits) + for (auto const &[w, l] : wlits) weight += w; if (weight < k) { if (lit == sat::null_literal) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index c89628808..65e51fe03 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1563,6 +1563,7 @@ public: return FC_CONTINUE; } for (expr* e : m_not_handled) { + (void) e; // just in case TRACE() is a no-op TRACE("arith", tout << "unhandled operator " << mk_pp(e, m) << "\n";); st = FC_GIVEUP; } diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 5c7ec827c..dc906cb32 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -110,7 +110,6 @@ protected: void operator()(quantifier * q) { m_stats["quantifiers"]++; SASSERT(is_app(q->get_expr())); - app * body = to_app(q->get_expr()); switch (q->get_kind()) { case forall_k: m_stats["forall-variables"] += q->get_num_decls(); From 2e15e2aa4d01357223404ab4f9ab9d201a8fe9ab Mon Sep 17 00:00:00 2001 From: mbergen Date: Wed, 16 Feb 2022 22:37:20 +0100 Subject: [PATCH 042/258] Add access to builtin special relations (`Context::mkLinearOrder` and `Context::mkPartialOrder` ) to Java API (#5832) * Add mkLinearOrder * reorder arguments to match definition, add short comment * add partial order * add comments --- src/api/java/Context.java | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index b22bedef7..c6d928de2 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -4038,6 +4038,37 @@ public class Context implements AutoCloseable { return new BitVecExpr(this, Native.mkFpaToFpIntReal(nCtx(), rm.getNativeObject(), exp.getNativeObject(), sig.getNativeObject(), s.getNativeObject())); } + /** + * Creates or a linear order. + * @param index The index of the order. + * @param sort The sort of the order. + */ + public FuncDecl mkLinearOrder(R sort, int index) { + return (FuncDecl) FuncDecl.create( + this, + Native.mkLinearOrder( + nCtx(), + sort.getNativeObject(), + index + ) + ); + } + + /** + * Creates or a partial order. + * @param index The index of the order. + * @param sort The sort of the order. + */ + public FuncDecl mkPartialOrder(R sort, int index) { + return (FuncDecl) FuncDecl.create( + this, + Native.mkPartialOrder( + nCtx(), + sort.getNativeObject(), + index + ) + ); + } /** * Wraps an AST. From 2e00f2f32db7a05dbecbdb75ca7a1e1918a6a0a8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Feb 2022 09:21:41 +0200 Subject: [PATCH 043/258] Propagator (#5845) * user propagator without ids Signed-off-by: Nikolaj Bjorner * user propagator without ids Signed-off-by: Nikolaj Bjorner * fix signature Signed-off-by: Nikolaj Bjorner * references #5818 Signed-off-by: Nikolaj Bjorner * fix c++ build Signed-off-by: Nikolaj Bjorner * switch to vs 2022 Signed-off-by: Nikolaj Bjorner * switch 2022 Signed-off-by: Nikolaj Bjorner * Update propagator example (I) (#5835) * fix #5829 * na Signed-off-by: Nikolaj Bjorner * switch to vs 2022 Signed-off-by: Nikolaj Bjorner * Adapted the example to the changes in the propagator Co-authored-by: Nikolaj Bjorner * context goes out of scope in stack allocation, so can't used scoped context when passing objects around * parameter check Signed-off-by: Nikolaj Bjorner * add rewriter Signed-off-by: Nikolaj Bjorner * Fixed bug in user-propagator "created" (#5843) Co-authored-by: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> --- examples/userPropagator/example.cpp | 84 +++++++++----- src/api/api_solver.cpp | 27 +++-- src/api/c++/z3++.h | 108 +++++++++--------- src/api/python/z3/z3.py | 22 ++-- src/api/z3_api.h | 18 +-- src/sat/sat_solver/inc_sat_solver.cpp | 4 +- src/sat/smt/euf_solver.h | 4 +- src/sat/smt/user_solver.cpp | 36 +++--- src/sat/smt/user_solver.h | 17 +-- src/smt/smt_context.h | 4 +- src/smt/smt_kernel.cpp | 4 +- src/smt/smt_kernel.h | 2 +- src/smt/smt_solver.cpp | 4 +- src/smt/tactic/smt_tactic_core.cpp | 141 ++---------------------- src/smt/theory_user_propagator.cpp | 49 ++++---- src/smt/theory_user_propagator.h | 33 ++++-- src/solver/tactic2solver.cpp | 4 +- src/tactic/core/elim_uncnstr_tactic.cpp | 3 +- src/tactic/core/reduce_args_tactic.cpp | 5 +- src/tactic/tactic.h | 2 +- src/tactic/tactical.cpp | 6 +- src/tactic/user_propagator_base.h | 12 +- 22 files changed, 261 insertions(+), 328 deletions(-) diff --git a/examples/userPropagator/example.cpp b/examples/userPropagator/example.cpp index b66e3bb0e..1b6888798 100644 --- a/examples/userPropagator/example.cpp +++ b/examples/userPropagator/example.cpp @@ -50,15 +50,36 @@ struct model_hash_function { } }; +namespace std { + + template<> + struct hash { + std::size_t operator()(const z3::expr &k) const { + return k.hash(); + } + }; +} + +// Do not use Z3's == operator in the hash table +namespace std { + + template<> + struct equal_to { + bool operator()(const z3::expr &lhs, const z3::expr &rhs) const { + return z3::eq(lhs, rhs); + } + }; +} + class user_propagator : public z3::user_propagator_base { protected: unsigned board; - std::unordered_map& id_mapping; + std::unordered_map& id_mapping; model currentModel; std::unordered_set modelSet; - std::vector fixedValues; + std::vector fixedValues; std::stack fixedCnt; int solutionId = 1; @@ -70,7 +91,10 @@ public: } void final() final { - this->conflict((unsigned) fixedValues.size(), fixedValues.data()); + z3::expr_vector conflicting(fixedValues[0].ctx()); + for (auto&& v : fixedValues) + conflicting.push_back(v); + this->conflict(conflicting); if (modelSet.find(currentModel) != modelSet.end()) { WriteLine("Got already computed model"); return; @@ -91,20 +115,20 @@ public: return (unsigned)e.get_numeral_int(); } - void fixed(unsigned id, z3::expr const &e) override { - fixedValues.push_back(id); - unsigned value = bvToInt(e); - currentModel[id_mapping[id]] = value; + void fixed(z3::expr const &ast, z3::expr const &value) override { + fixedValues.push_back(ast); + unsigned valueBv = bvToInt(value); + currentModel[id_mapping[ast]] = valueBv; } - user_propagator(z3::solver *s, std::unordered_map& idMapping, unsigned board) + user_propagator(z3::solver *s, std::unordered_map& idMapping, unsigned board) : user_propagator_base(s), board(board), id_mapping(idMapping), currentModel(board, (unsigned)-1) { this->register_fixed(); this->register_final(); } - virtual ~user_propagator() = default; + ~user_propagator() = default; void push() override { fixedCnt.push((unsigned) fixedValues.size()); @@ -117,50 +141,58 @@ public: for (auto j = fixedValues.size(); j > lastCnt; j--) { currentModel[fixedValues[j - 1]] = (unsigned)-1; } - fixedValues.resize(lastCnt); + fixedValues.erase(fixedValues.cbegin() + lastCnt, fixedValues.cend()); } } - user_propagator_base *fresh(Z3_context) override { return this; } + user_propagator_base *fresh(Z3_context) override { + return this; + } }; class user_propagator_with_theory : public user_propagator { public: - void fixed(unsigned id, z3::expr const &e) override { - unsigned queenId = id_mapping[id]; - unsigned queenPos = bvToInt(e); + void fixed(z3::expr const &ast, z3::expr const &value) override { + unsigned queenId = id_mapping[ast]; + unsigned queenPos = bvToInt(value); if (queenPos >= board) { - this->conflict(1, &id); + z3::expr_vector conflicting(ast.ctx()); + conflicting.push_back(ast); + this->conflict(conflicting); return; } - for (unsigned fixed : fixedValues) { + for (z3::expr fixed : fixedValues) { unsigned otherId = id_mapping[fixed]; unsigned otherPos = currentModel[fixed]; if (queenPos == otherPos) { - const unsigned conflicting[] = {id, fixed}; - this->conflict(2, conflicting); + z3::expr_vector conflicting(ast.ctx()); + conflicting.push_back(ast); + conflicting.push_back(fixed); + this->conflict(conflicting); continue; } #ifdef QUEEN int diffY = abs((int)queenId - (int)otherId); int diffX = abs((int)queenPos - (int)otherPos); if (diffX == diffY) { - const unsigned conflicting[] = {id, fixed}; - this->conflict(2, conflicting); + z3::expr_vector conflicting(ast.ctx()); + conflicting.push_back(ast); + conflicting.push_back(fixed); + this->conflict(conflicting); } #endif } - fixedValues.push_back(id); - currentModel[id_mapping[id]] = queenPos; + fixedValues.push_back(ast); + currentModel[id_mapping[ast]] = queenPos; } - user_propagator_with_theory(z3::solver *s, std::unordered_map& idMapping, unsigned board) + user_propagator_with_theory(z3::solver *s, std::unordered_map& idMapping, unsigned board) : user_propagator(s, idMapping, board) {} }; @@ -261,7 +293,7 @@ inline int test1(unsigned num) { int test23(unsigned num, bool withTheory) { z3::context context; z3::solver solver(context, Z3_mk_simple_solver(context)); - std::unordered_map idMapping; + std::unordered_map idMapping; user_propagator *propagator; if (!withTheory) { @@ -274,8 +306,8 @@ int test23(unsigned num, bool withTheory) { std::vector queens = createQueens(context, num); for (unsigned i = 0; i < queens.size(); i++) { - unsigned id = propagator->add(queens[i]); - idMapping[id] = i; + propagator->add(queens[i]); + idMapping[queens[i]] = i; } if (!withTheory) { diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 43211b3b8..99d332724 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -902,7 +902,7 @@ extern "C" { Z3_fixed_eh fixed_eh) { Z3_TRY; RESET_ERROR_CODE(); - user_propagator::fixed_eh_t _fixed = (void(*)(void*,user_propagator::callback*,unsigned,expr*))fixed_eh; + user_propagator::fixed_eh_t _fixed = (void(*)(void*,user_propagator::callback*,expr*,expr*))fixed_eh; to_solver_ref(s)->user_propagate_register_fixed(_fixed); Z3_CATCH; } @@ -924,7 +924,7 @@ extern "C" { Z3_eq_eh eq_eh) { Z3_TRY; RESET_ERROR_CODE(); - user_propagator::eq_eh_t _eq = (void(*)(void*,user_propagator::callback*,unsigned,unsigned))eq_eh; + user_propagator::eq_eh_t _eq = (void(*)(void*,user_propagator::callback*,expr*,expr*))eq_eh; to_solver_ref(s)->user_propagate_register_eq(_eq); Z3_CATCH; } @@ -935,39 +935,42 @@ extern "C" { Z3_eq_eh diseq_eh) { Z3_TRY; RESET_ERROR_CODE(); - user_propagator::eq_eh_t _diseq = (void(*)(void*,user_propagator::callback*,unsigned,unsigned))diseq_eh; + user_propagator::eq_eh_t _diseq = (void(*)(void*,user_propagator::callback*,expr*,expr*))diseq_eh; to_solver_ref(s)->user_propagate_register_diseq(_diseq); Z3_CATCH; } - unsigned Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e) { + void Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e) { Z3_TRY; LOG_Z3_solver_propagate_register(c, s, e); RESET_ERROR_CODE(); - return to_solver_ref(s)->user_propagate_register_expr(to_expr(e)); - Z3_CATCH_RETURN(0); + to_solver_ref(s)->user_propagate_register_expr(to_expr(e)); + Z3_CATCH; } - unsigned Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback s, Z3_ast e) { + void Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback s, Z3_ast e) { Z3_TRY; LOG_Z3_solver_propagate_register_cb(c, s, e); RESET_ERROR_CODE(); - return reinterpret_cast(s)->register_cb(to_expr(e)); - Z3_CATCH_RETURN(0); + reinterpret_cast(s)->register_cb(to_expr(e)); + Z3_CATCH; } - void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq) { + void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, Z3_ast const* fixed_ids, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq) { Z3_TRY; LOG_Z3_solver_propagate_consequence(c, s, num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, conseq); RESET_ERROR_CODE(); - reinterpret_cast(s)->propagate_cb(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, to_expr(conseq)); + expr* const * _fixed_ids = (expr* const*) fixed_ids; + expr* const * _eq_lhs = (expr*const*) eq_lhs; + expr* const * _eq_rhs = (expr*const*) eq_rhs; + reinterpret_cast(s)->propagate_cb(num_fixed, _fixed_ids, num_eqs, _eq_lhs, _eq_rhs, to_expr(conseq)); Z3_CATCH; } void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh) { Z3_TRY; RESET_ERROR_CODE(); - user_propagator::created_eh_t c = (void(*)(void*, user_propagator::callback*, expr*, unsigned))created_eh; + user_propagator::created_eh_t c = (void(*)(void*, user_propagator::callback*, expr*))created_eh; to_solver_ref(s)->user_propagate_register_created(c); Z3_CATCH; } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b7547b990..0bbab4185 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -155,9 +155,10 @@ namespace z3 { class context { private: + friend class user_propagator_base; bool m_enable_exceptions; rounding_mode m_rounding_mode; - Z3_context m_ctx; + Z3_context m_ctx = nullptr; void init(config & c) { set_context(Z3_mk_context_rc(c)); } @@ -173,7 +174,6 @@ namespace z3 { context(context const &) = delete; context & operator=(context const &) = delete; - friend class scoped_context; context(Z3_context c) { set_context(c); } void detach() { m_ctx = nullptr; } public: @@ -394,14 +394,6 @@ namespace z3 { expr_vector parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); }; - class scoped_context final { - context m_ctx; - public: - scoped_context(Z3_context c): m_ctx(c) {} - ~scoped_context() { m_ctx.detach(); } - context& operator()() { return m_ctx; } - }; - template class array { @@ -509,7 +501,7 @@ namespace z3 { ast(context & c):object(c), m_ast(0) {} ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); } ast(ast const & s) :object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); } - ~ast() { if (m_ast) Z3_dec_ref(*m_ctx, m_ast); } + ~ast() { if (m_ast) { Z3_dec_ref(*m_ctx, m_ast); } } operator Z3_ast() const { return m_ast; } operator bool() const { return m_ast != 0; } ast & operator=(ast const & s) { @@ -3933,23 +3925,20 @@ namespace z3 { class user_propagator_base { - typedef std::function fixed_eh_t; + typedef std::function fixed_eh_t; typedef std::function final_eh_t; - typedef std::function eq_eh_t; - typedef std::function created_eh_t; + typedef std::function eq_eh_t; + typedef std::function created_eh_t; final_eh_t m_final_eh; eq_eh_t m_eq_eh; fixed_eh_t m_fixed_eh; created_eh_t m_created_eh; solver* s; - Z3_context c; + context* c; + Z3_solver_callback cb { nullptr }; - Z3_context ctx() { - return c ? c : (Z3_context)s->ctx(); - } - struct scoped_cb { user_propagator_base& p; scoped_cb(void* _p, Z3_solver_callback cb):p(*static_cast(_p)) { @@ -3972,17 +3961,19 @@ namespace z3 { return static_cast(p)->fresh(ctx); } - static void fixed_eh(void* _p, Z3_solver_callback cb, unsigned id, Z3_ast _value) { + static void fixed_eh(void* _p, Z3_solver_callback cb, Z3_ast _var, Z3_ast _value) { user_propagator_base* p = static_cast(_p); scoped_cb _cb(p, cb); - scoped_context ctx(p->ctx()); - expr value(ctx(), _value); - static_cast(p)->m_fixed_eh(id, value); + expr value(p->ctx(), _value); + expr var(p->ctx(), _var); + p->m_fixed_eh(var, value); } - static void eq_eh(void* p, Z3_solver_callback cb, unsigned x, unsigned y) { + static void eq_eh(void* _p, Z3_solver_callback cb, Z3_ast _x, Z3_ast _y) { + user_propagator_base* p = static_cast(_p); scoped_cb _cb(p, cb); - static_cast(p)->m_eq_eh(x, y); + expr x(p->ctx(), _x), y(p->ctx(), _y); + p->m_eq_eh(x, y); } static void final_eh(void* p, Z3_solver_callback cb) { @@ -3990,17 +3981,16 @@ namespace z3 { static_cast(p)->m_final_eh(); } - static void created_eh(void* _p, Z3_solver_callback cb, Z3_ast _e, unsigned id) { + static void created_eh(void* _p, Z3_solver_callback cb, Z3_ast _e) { user_propagator_base* p = static_cast(_p); scoped_cb _cb(p, cb); - scoped_context ctx(p->ctx()); - expr e(ctx(), _e); - static_cast(p)->m_created_eh(id, e); + expr e(p->ctx(), _e); + p->m_created_eh(e); } public: - user_propagator_base(Z3_context c) : s(nullptr), c(c) {} + user_propagator_base(context& c) : s(nullptr), c(&c) {} user_propagator_base(solver* s): s(s), c(nullptr) { Z3_solver_propagate_init(ctx(), *s, this, push_eh, pop_eh, fresh_eh); @@ -4011,6 +4001,10 @@ namespace z3 { virtual ~user_propagator_base() = default; + context& ctx() { + return c ? *c : s->ctx(); + } + /** \brief user_propagators created using \c fresh() are created during search and their lifetimes are restricted to search time. They should @@ -4035,7 +4029,7 @@ namespace z3 { void register_fixed() { assert(s); - m_fixed_eh = [this](unsigned id, expr const& e) { + m_fixed_eh = [this](expr const& id, expr const& e) { fixed(id, e); }; Z3_solver_propagate_fixed(ctx(), *s, fixed_eh); @@ -4049,7 +4043,7 @@ namespace z3 { void register_eq() { assert(s); - m_eq_eh = [this](unsigned x, unsigned y) { + m_eq_eh = [this](expr const& x, expr const& y) { eq(x, y); }; Z3_solver_propagate_eq(ctx(), *s, eq_eh); @@ -4084,19 +4078,19 @@ namespace z3 { } void register_created() { - m_created_eh = [this](unsigned id, expr const& e) { - created(id, e); + m_created_eh = [this](expr const& e) { + created(e); }; Z3_solver_propagate_created(ctx(), *s, created_eh); } - virtual void fixed(unsigned /*id*/, expr const& /*e*/) { } + virtual void fixed(expr const& /*id*/, expr const& /*e*/) { } - virtual void eq(unsigned /*x*/, unsigned /*y*/) { } + virtual void eq(expr const& /*x*/, expr const& /*y*/) { } virtual void final() { } - virtual void created(unsigned /*id*/, expr const& /*e*/) {} + virtual void created(expr const& /*e*/) {} /** \brief tracks \c e by a unique identifier that is returned by the call. @@ -4112,34 +4106,40 @@ namespace z3 { correspond to equalities that have been registered during a callback. */ - unsigned add(expr const& e) { + void add(expr const& e) { if (cb) - return Z3_solver_propagate_register_cb(ctx(), cb, e); - if (s) - return Z3_solver_propagate_register(ctx(), *s, e); - assert(false); - return 0; + Z3_solver_propagate_register_cb(ctx(), cb, e); + else if (s) + Z3_solver_propagate_register(ctx(), *s, e); + else + assert(false); } - void conflict(unsigned num_fixed, unsigned const* fixed) { + void conflict(expr_vector const& fixed) { assert(cb); - scoped_context _ctx(ctx()); - expr conseq = _ctx().bool_val(false); - Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, 0, nullptr, nullptr, conseq); + expr conseq = ctx().bool_val(false); + array _fixed(fixed); + Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq); } - void propagate(unsigned num_fixed, unsigned const* fixed, expr const& conseq) { + void propagate(expr_vector const& fixed, expr const& conseq) { assert(cb); - assert(conseq.ctx() == ctx()); - Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, 0, nullptr, nullptr, conseq); + assert((Z3_context)conseq.ctx() == (Z3_context)ctx()); + array _fixed(fixed); + Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq); } - void propagate(unsigned num_fixed, unsigned const* fixed, - unsigned num_eqs, unsigned const* lhs, unsigned const * rhs, + void propagate(expr_vector const& fixed, + expr_vector const& lhs, expr_vector const& rhs, expr const& conseq) { assert(cb); - assert(conseq.ctx() == ctx()); - Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, num_eqs, lhs, rhs, conseq); + assert((Z3_context)conseq.ctx() == (Z3_context)ctx()); + assert(lhs.size() == rhs.size()); + array _fixed(fixed); + array _lhs(lhs); + array _rhs(rhs); + + Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq); } }; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 727f289a1..1a35865c9 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11261,7 +11261,7 @@ def user_prop_fresh(id, ctx): def user_prop_fixed(ctx, cb, id, value): prop = _prop_closures.get(ctx) prop.cb = cb - prop.fixed(id, _to_expr_ref(ctypes.c_void_p(value), prop.ctx())) + prop.fixed(_to_expr_ref(ctypes.c_void_p(id), prop.ctx()), _to_expr_ref(ctypes.c_void_p(value), prop.ctx())) prop.cb = None @@ -11275,6 +11275,8 @@ def user_prop_final(ctx, cb): def user_prop_eq(ctx, cb, x, y): prop = _prop_closures.get(ctx) prop.cb = cb + x = _to_expr_ref(ctypes.c_void_p(x), prop.ctx()) + y = _to_expr_ref(ctypes.c_void_p(y), prop.ctx()) prop.eq(x, y) prop.cb = None @@ -11282,6 +11284,8 @@ def user_prop_eq(ctx, cb, x, y): def user_prop_diseq(ctx, cb, x, y): prop = _prop_closures.get(ctx) prop.cb = cb + x = _to_expr_ref(ctypes.c_void_p(x), prop.ctx()) + y = _to_expr_ref(ctypes.c_void_p(y), prop.ctx()) prop.diseq(x, y) prop.cb = None @@ -11385,18 +11389,12 @@ class UserPropagateBase: # Propagation can only be invoked as during a fixed or final callback. # def propagate(self, e, ids, eqs=[]): - num_fixed = len(ids) - _ids = (ctypes.c_uint * num_fixed)() - for i in range(num_fixed): - _ids[i] = ids[i] + _ids, num_fixed = _to_ast_array(ids) num_eqs = len(eqs) - _lhs = (ctypes.c_uint * num_eqs)() - _rhs = (ctypes.c_uint * num_eqs)() - for i in range(num_eqs): - _lhs[i] = eqs[i][0] - _rhs[i] = eqs[i][1] + _lhs, _num_lhs = _to_ast_array([x for x, y in eqs]) + _rhs, _num_lhs = _to_ast_array([y for x, y in eqs]) Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p( self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast) - def conflict(self, ids): - self.propagate(BoolVal(False, self.ctx()), ids, eqs=[]) + def conflict(self, deps): + self.propagate(BoolVal(False, self.ctx()), deps, eqs=[]) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 16d3a292c..95c04ea17 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1433,10 +1433,10 @@ Z3_DECLARE_CLOSURE(Z3_error_handler, void, (Z3_context c, Z3_error_code e)); Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx)); Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, unsigned num_scopes)); Z3_DECLARE_CLOSURE(Z3_fresh_eh, void*, (void* ctx, Z3_context new_context)); -Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, unsigned id, Z3_ast value)); -Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, unsigned x, unsigned y)); +Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t, Z3_ast value)); +Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb)); -Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast e, unsigned id)); +Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t)); /** @@ -6761,10 +6761,10 @@ extern "C" { \brief register an expression to propagate on with the solver. Only expressions of type Bool and type Bit-Vector can be registered for propagation. - def_API('Z3_solver_propagate_register', UINT, (_in(CONTEXT), _in(SOLVER), _in(AST))) + def_API('Z3_solver_propagate_register', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST))) */ - unsigned Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e); + void Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e); /** \brief register an expression to propagate on with the solver. @@ -6772,9 +6772,9 @@ extern "C" { Unlike \ref Z3_solver_propagate_register, this function takes a solver callback context as argument. It can be invoked during a callback to register new expressions. - def_API('Z3_solver_propagate_register_cb', UINT, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST))) + def_API('Z3_solver_propagate_register_cb', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST))) */ - unsigned Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback cb, Z3_ast e); + void Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback cb, Z3_ast e); /** \brief propagate a consequence based on fixed values. @@ -6782,10 +6782,10 @@ extern "C" { The callback adds a propagation consequence based on the fixed values of the \c ids. - def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, UINT), _in(UINT), _in_array(4, UINT), _in_array(4, UINT), _in(AST))) + def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST))) */ - void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq); + void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq); /** \brief Check whether the assertions in a given solver are consistent or not. diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index db1f28743..61dc53cd8 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -683,8 +683,8 @@ public: ensure_euf()->user_propagate_register_diseq(diseq_eh); } - unsigned user_propagate_register_expr(expr* e) override { - return ensure_euf()->user_propagate_register_expr(e); + void user_propagate_register_expr(expr* e) override { + ensure_euf()->user_propagate_register_expr(e); } void user_propagate_register_created(user_propagator::created_eh_t& r) override { diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index d299c92d0..669eb1616 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -434,9 +434,9 @@ namespace euf { check_for_user_propagator(); m_user_propagator->register_created(ceh); } - unsigned user_propagate_register_expr(expr* e) { + void user_propagate_register_expr(expr* e) { check_for_user_propagator(); - return m_user_propagator->add_expr(e); + m_user_propagator->add_expr(e); } // solver factory diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index febbe9383..6b3eb6718 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -28,31 +28,33 @@ namespace user_solver { dealloc(m_api_context); } - unsigned solver::add_expr(expr* e) { + void solver::add_expr(expr* e) { force_push(); ctx.internalize(e, false); euf::enode* n = expr2enode(e); if (is_attached_to_var(n)) - return n->get_th_var(get_id()); + return; euf::theory_var v = mk_var(n); ctx.attach_th_var(n, this, v); expr_ref r(m); sat::literal_vector explain; if (ctx.is_fixed(n, r, explain)) - m_prop.push_back(prop_info(explain, v, r)); - return v; + m_prop.push_back(prop_info(explain, v, r)); } void solver::propagate_cb( - unsigned num_fixed, unsigned const* fixed_ids, - unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, + unsigned num_fixed, expr* const* fixed_ids, + unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr* conseq) { - m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, expr_ref(conseq, m))); + m_fixed_ids.reset(); + for (unsigned i = 0; i < num_fixed; ++i) + m_fixed_ids.push_back(get_th_var(fixed_ids[i])); + m_prop.push_back(prop_info(num_fixed, m_fixed_ids.data(), num_eqs, eq_lhs, eq_rhs, expr_ref(conseq, m))); DEBUG_CODE(validate_propagation();); } - unsigned solver::register_cb(expr* e) { - return add_expr(e); + void solver::register_cb(expr* e) { + add_expr(e); } sat::check_result solver::check() { @@ -68,7 +70,7 @@ namespace user_solver { return; force_push(); m_id2justification.setx(v, sat::literal_vector(num_lits, jlits), sat::literal_vector()); - m_fixed_eh(m_user_context, this, v, value); + m_fixed_eh(m_user_context, this, var2expr(v), value); } void solver::asserted(sat::literal lit) { @@ -80,7 +82,7 @@ namespace user_solver { sat::literal_vector lits; lits.push_back(lit); m_id2justification.setx(v, lits, sat::literal_vector()); - m_fixed_eh(m_user_context, this, v, lit.sign() ? m.mk_false() : m.mk_true()); + m_fixed_eh(m_user_context, this, var2expr(v), lit.sign() ? m.mk_false() : m.mk_true()); } void solver::push_core() { @@ -141,9 +143,9 @@ namespace user_solver { auto& j = justification::from_index(idx); auto const& prop = m_prop[j.m_propagation_index]; for (unsigned id : prop.m_ids) - r.append(m_id2justification[id]); + r.append(m_id2justification[id]); for (auto const& p : prop.m_eqs) - ctx.add_antecedent(var2enode(p.first), var2enode(p.second)); + ctx.add_antecedent(expr2enode(p.first), expr2enode(p.second)); } /* @@ -156,7 +158,7 @@ namespace user_solver { for (auto lit: m_id2justification[id]) VERIFY(s().value(lit) == l_true); for (auto const& p : prop.m_eqs) - VERIFY(var2enode(p.first)->get_root() == var2enode(p.second)->get_root()); + VERIFY(expr2enode(p.first)->get_root() == expr2enode(p.second)->get_root()); } std::ostream& solver::display(std::ostream& out) const { @@ -171,7 +173,7 @@ namespace user_solver { for (unsigned id : prop.m_ids) out << id << ": " << m_id2justification[id]; for (auto const& p : prop.m_eqs) - out << "v" << p.first << " == v" << p.second << " "; + out << "v" << mk_pp(p.first, m) << " == v" << mk_pp(p.second, m) << " "; return out; } @@ -224,9 +226,9 @@ namespace user_solver { SASSERT(!n || !n->is_attached_to(get_id())); if (!n) n = mk_enode(e, false); - auto v = add_expr(e); + add_expr(e); if (m_created_eh) - m_created_eh(m_user_context, this, e, v); + m_created_eh(m_user_context, this, e); return true; } diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index a30bc6a6d..13948db81 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -29,13 +29,13 @@ namespace user_solver { class solver : public euf::th_euf_solver, public user_propagator::callback { struct prop_info { - unsigned_vector m_ids; - expr_ref m_conseq; - svector> m_eqs; + unsigned_vector m_ids; + expr_ref m_conseq; + svector> m_eqs; sat::literal_vector m_lits; - euf::theory_var m_var = euf::null_theory_var; + euf::theory_var m_var = euf::null_theory_var; - prop_info(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr_ref const& c): + prop_info(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr_ref const& c): m_ids(num_fixed, fixed_ids), m_conseq(c) { @@ -72,6 +72,7 @@ namespace user_solver { vector m_id2justification; sat::literal_vector m_lits; euf::enode_pair_vector m_eqs; + unsigned_vector m_fixed_ids; stats m_stats; struct justification { @@ -118,7 +119,7 @@ namespace user_solver { m_fresh_eh = fresh_eh; } - unsigned add_expr(expr* e); + void add_expr(expr* e); void register_final(user_propagator::final_eh_t& final_eh) { m_final_eh = final_eh; } void register_fixed(user_propagator::fixed_eh_t& fixed_eh) { m_fixed_eh = fixed_eh; } @@ -128,8 +129,8 @@ namespace user_solver { bool has_fixed() const { return (bool)m_fixed_eh; } - void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* lhs, unsigned const* rhs, expr* conseq) override; - unsigned register_cb(expr* e) override; + void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override; + void register_cb(expr* e) override; void new_fixed_eh(euf::theory_var v, expr* value, unsigned num_lits, sat::literal const* jlits); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index b8c8a7ee9..12f0cc2ad 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1726,10 +1726,10 @@ namespace smt { m_user_propagator->register_diseq(diseq_eh); } - unsigned user_propagate_register_expr(expr* e) { + void user_propagate_register_expr(expr* e) { if (!m_user_propagator) throw default_exception("user propagator must be initialized"); - return m_user_propagator->add_expr(e); + m_user_propagator->add_expr(e); } void user_propagate_register_created(user_propagator::created_eh_t& r) { diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 347260c84..87e5fd36d 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -276,8 +276,8 @@ namespace smt { m_imp->m_kernel.user_propagate_register_diseq(diseq_eh); } - unsigned kernel::user_propagate_register_expr(expr* e) { - return m_imp->m_kernel.user_propagate_register_expr(e); + void kernel::user_propagate_register_expr(expr* e) { + m_imp->m_kernel.user_propagate_register_expr(e); } void kernel::user_propagate_register_created(user_propagator::created_eh_t& r) { diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 28680e7a6..77ad2559c 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -307,7 +307,7 @@ namespace smt { void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh); - unsigned user_propagate_register_expr(expr* e); + void user_propagate_register_expr(expr* e); void user_propagate_register_created(user_propagator::created_eh_t& r); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 1cb9b26e1..ad67c19d1 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -236,8 +236,8 @@ namespace { m_context.user_propagate_register_diseq(diseq_eh); } - unsigned user_propagate_register_expr(expr* e) override { - return m_context.user_propagate_register_expr(e); + void user_propagate_register_expr(expr* e) override { + m_context.user_propagate_register_expr(e); } void user_propagate_register_created(user_propagator::created_eh_t& c) override { diff --git a/src/smt/tactic/smt_tactic_core.cpp b/src/smt/tactic/smt_tactic_core.cpp index bf2ea9bd6..072e1ed24 100644 --- a/src/smt/tactic/smt_tactic_core.cpp +++ b/src/smt/tactic/smt_tactic_core.cpp @@ -40,6 +40,7 @@ class smt_tactic : public tactic { ast_manager& m; smt_params m_params; params_ref m_params_ref; + expr_ref_vector m_vars; statistics m_stats; smt::kernel* m_ctx = nullptr; symbol m_logic; @@ -321,141 +322,20 @@ public: user_propagator::eq_eh_t m_eq_eh; user_propagator::eq_eh_t m_diseq_eh; user_propagator::created_eh_t m_created_eh; - - expr_ref_vector m_vars; - unsigned_vector m_var2internal; - unsigned_vector m_internal2var; - unsigned_vector m_limit; - user_propagator::push_eh_t i_push_eh; - user_propagator::pop_eh_t i_pop_eh; - user_propagator::fixed_eh_t i_fixed_eh; - user_propagator::final_eh_t i_final_eh; - user_propagator::eq_eh_t i_eq_eh; - user_propagator::eq_eh_t i_diseq_eh; - user_propagator::created_eh_t i_created_eh; - - - struct callback : public user_propagator::callback { - smt_tactic* t = nullptr; - user_propagator::callback* cb = nullptr; - unsigned_vector fixed, lhs, rhs; - void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr* conseq) override { - fixed.reset(); - lhs.reset(); - rhs.reset(); - for (unsigned i = 0; i < num_fixed; ++i) - fixed.push_back(t->m_var2internal[fixed_ids[i]]); - for (unsigned i = 0; i < num_eqs; ++i) { - lhs.push_back(t->m_var2internal[eq_lhs[i]]); - rhs.push_back(t->m_var2internal[eq_rhs[i]]); - } - cb->propagate_cb(num_fixed, fixed.data(), num_eqs, lhs.data(), rhs.data(), conseq); - } - - unsigned register_cb(expr* e) override { - unsigned j = t->m_vars.size(); - t->m_vars.push_back(e); - unsigned i = cb->register_cb(e); - t->m_var2internal.setx(j, i, 0); - t->m_internal2var.setx(i, j, 0); - return j; - } - }; - - callback i_cb; - - void init_i_fixed_eh() { - if (!m_fixed_eh) - return; - i_fixed_eh = [this](void* ctx, user_propagator::callback* cb, unsigned id, expr* value) { - i_cb.t = this; - i_cb.cb = cb; - m_fixed_eh(ctx, &i_cb, m_internal2var[id], value); - }; - m_ctx->user_propagate_register_fixed(i_fixed_eh); - } - - void init_i_final_eh() { - if (!m_final_eh) - return; - i_final_eh = [this](void* ctx, user_propagator::callback* cb) { - i_cb.t = this; - i_cb.cb = cb; - m_final_eh(ctx, &i_cb); - }; - m_ctx->user_propagate_register_final(i_final_eh); - } - - void init_i_eq_eh() { - if (!m_eq_eh) - return; - i_eq_eh = [this](void* ctx, user_propagator::callback* cb, unsigned u, unsigned v) { - i_cb.t = this; - i_cb.cb = cb; - m_eq_eh(ctx, &i_cb, m_internal2var[u], m_internal2var[v]); - }; - m_ctx->user_propagate_register_eq(i_eq_eh); - } - - void init_i_diseq_eh() { - if (!m_diseq_eh) - return; - i_diseq_eh = [this](void* ctx, user_propagator::callback* cb, unsigned u, unsigned v) { - i_cb.t = this; - i_cb.cb = cb; - m_diseq_eh(ctx, &i_cb, m_internal2var[u], m_internal2var[v]); - }; - m_ctx->user_propagate_register_diseq(i_diseq_eh); - } - - void init_i_created_eh() { - if (!m_created_eh) - return; - i_created_eh = [this](void* ctx, user_propagator::callback* cb, expr* e, unsigned i) { - unsigned j = m_vars.size(); - m_vars.push_back(e); - m_internal2var.setx(i, j, 0); - m_var2internal.setx(j, i, 0); - m_created_eh(ctx, cb, e, j); - }; - m_ctx->user_propagate_register_created(i_created_eh); - } - - void init_i_push_pop() { - i_push_eh = [this](void* ctx) { - m_limit.push_back(m_vars.size()); - m_push_eh(ctx); - }; - i_pop_eh = [this](void* ctx, unsigned n) { - unsigned old_sz = m_limit.size() - n; - unsigned num_vars = m_limit[old_sz]; - m_vars.shrink(num_vars); - m_limit.shrink(old_sz); - m_pop_eh(ctx, n); - }; - } - - void user_propagate_delay_init() { if (!m_user_ctx) return; - init_i_push_pop(); - m_ctx->user_propagate_init(m_user_ctx, i_push_eh, i_pop_eh, m_fresh_eh); - init_i_fixed_eh(); - init_i_final_eh(); - init_i_eq_eh(); - init_i_diseq_eh(); - init_i_created_eh(); + m_ctx->user_propagate_init(m_user_ctx, m_push_eh, m_pop_eh, m_fresh_eh); + if (m_fixed_eh) m_ctx->user_propagate_register_fixed(m_fixed_eh); + if (m_final_eh) m_ctx->user_propagate_register_final(m_final_eh); + if (m_eq_eh) m_ctx->user_propagate_register_eq(m_eq_eh); + if (m_diseq_eh) m_ctx->user_propagate_register_diseq(m_diseq_eh); + if (m_created_eh) m_ctx->user_propagate_register_created(m_created_eh); - unsigned i = 0; - for (expr* v : m_vars) { - unsigned j = m_ctx->user_propagate_register_expr(v); - m_var2internal.setx(i, j, 0); - m_internal2var.setx(j, i, 0); - ++i; - } + for (expr* v : m_vars) + m_ctx->user_propagate_register_expr(v); } void user_propagate_clear() override { @@ -496,9 +376,8 @@ public: m_diseq_eh = diseq_eh; } - unsigned user_propagate_register_expr(expr* e) override { + void user_propagate_register_expr(expr* e) override { m_vars.push_back(e); - return m_vars.size() - 1; } void user_propagate_register_created(user_propagator::created_eh_t& created_eh) override { diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 5e5bd1e1d..85a02b154 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -23,7 +23,8 @@ Author: using namespace smt; theory_user_propagator::theory_user_propagator(context& ctx): - theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name())) + theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name())), + m_var2expr(ctx.get_manager()) {} theory_user_propagator::~theory_user_propagator() { @@ -38,9 +39,10 @@ void theory_user_propagator::force_push() { } } -unsigned theory_user_propagator::add_expr(expr* e) { +void theory_user_propagator::add_expr(expr* term) { force_push(); expr_ref r(m); + expr* e = term; ctx.get_rewriter()(e, r); if (r != e) { r = m.mk_fresh_const("aux-expr", e->get_sort()); @@ -52,8 +54,14 @@ unsigned theory_user_propagator::add_expr(expr* e) { } enode* n = ensure_enode(e); if (is_attached_to_var(n)) - return n->get_th_var(get_id()); + return; + + theory_var v = mk_var(n); + m_var2expr.reserve(v + 1); + m_var2expr[v] = term; + m_expr2var.setx(term->get_id(), v, null_theory_var); + if (m.is_bool(e) && !ctx.b_internalized(e)) { bool_var bv = ctx.mk_bool_var(e); ctx.set_var_theory(bv, get_id()); @@ -65,22 +73,24 @@ unsigned theory_user_propagator::add_expr(expr* e) { literal_vector explain; if (ctx.is_fixed(n, r, explain)) m_prop.push_back(prop_info(explain, v, r)); - return v; + } void theory_user_propagator::propagate_cb( - unsigned num_fixed, unsigned const* fixed_ids, - unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, + unsigned num_fixed, expr* const* fixed_ids, + unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr* conseq) { CTRACE("user_propagate", ctx.lit_internalized(conseq) && ctx.get_assignment(ctx.get_literal(conseq)) == l_true, ctx.display(tout << "redundant consequence: " << mk_pp(conseq, m) << "\n")); - if (ctx.lit_internalized(conseq) && ctx.get_assignment(ctx.get_literal(conseq)) == l_true) + expr_ref _conseq(conseq, m); + ctx.get_rewriter()(conseq, _conseq); + if (ctx.lit_internalized(_conseq) && ctx.get_assignment(ctx.get_literal(_conseq)) == l_true) return; - m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, expr_ref(conseq, m))); + m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, _conseq)); } -unsigned theory_user_propagator::register_cb(expr* e) { - return add_expr(e); +void theory_user_propagator::register_cb(expr* e) { + add_expr(e); } theory * theory_user_propagator::mk_fresh(context * new_ctx) { @@ -91,6 +101,7 @@ theory * theory_user_propagator::mk_fresh(context * new_ctx) { if ((bool)m_final_eh) th->register_final(m_final_eh); if ((bool)m_eq_eh) th->register_eq(m_eq_eh); if ((bool)m_diseq_eh) th->register_diseq(m_diseq_eh); + if ((bool)m_created_eh) th->register_created(m_created_eh); return th; } @@ -114,7 +125,7 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu m_fixed.insert(v); ctx.push_trail(insert_map(m_fixed, v)); m_id2justification.setx(v, literal_vector(num_lits, jlits), literal_vector()); - m_fixed_eh(m_user_context, this, v, value); + m_fixed_eh(m_user_context, this, var2expr(v), value); } void theory_user_propagator::push_scope_eh() { @@ -142,12 +153,12 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) { justification* js; m_lits.reset(); m_eqs.reset(); - for (unsigned id : prop.m_ids) - m_lits.append(m_id2justification[id]); + for (expr* id : prop.m_ids) + m_lits.append(m_id2justification[expr2var(id)]); for (auto const& p : prop.m_eqs) - m_eqs.push_back(enode_pair(get_enode(p.first), get_enode(p.second))); + m_eqs.push_back(enode_pair(get_enode(expr2var(p.first)), get_enode(expr2var(p.second)))); DEBUG_CODE(for (auto const& p : m_eqs) VERIFY(p.first->get_root() == p.second->get_root());); - DEBUG_CODE(for (unsigned id : prop.m_ids) VERIFY(m_fixed.contains(id));); + DEBUG_CODE(for (expr* e : prop.m_ids) VERIFY(m_fixed.contains(expr2var(e)));); DEBUG_CODE(for (literal lit : m_lits) VERIFY(ctx.get_assignment(lit) == l_true);); TRACE("user_propagate", tout << "propagating #" << prop.m_conseq->get_id() << ": " << prop.m_conseq << "\n"); @@ -216,12 +227,12 @@ bool theory_user_propagator::internalize_term(app* term) { if (term->get_family_id() == get_id() && !ctx.e_internalized(term)) ctx.mk_enode(term, true, false, true); - unsigned v = add_expr(term); + add_expr(term); - if (!m_created_eh && (m_fixed_eh || m_eq_eh || m_diseq_eh)) - throw default_exception("You have to register a created event handler for new terms if you track them"); + if (!m_created_eh && (m_fixed_eh || m_eq_eh || m_diseq_eh)) + return true; if (m_created_eh) - m_created_eh(m_user_context, this, term, v); + m_created_eh(m_user_context, this, term); return true; } diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index f1e558256..e1aa33b8e 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -30,13 +30,13 @@ namespace smt { class theory_user_propagator : public theory, public user_propagator::callback { struct prop_info { - unsigned_vector m_ids; + ptr_vector m_ids; expr_ref m_conseq; - svector> m_eqs; + svector> m_eqs; literal_vector m_lits; - theory_var m_var = null_theory_var; - prop_info(unsigned num_fixed, unsigned const* fixed_ids, - unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr_ref const& c): + theory_var m_var = null_theory_var; + prop_info(unsigned num_fixed, expr* const* fixed_ids, + unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr_ref const& c): m_ids(num_fixed, fixed_ids), m_conseq(c) { for (unsigned i = 0; i < num_eqs; ++i) @@ -64,7 +64,7 @@ namespace smt { user_propagator::fixed_eh_t m_fixed_eh; user_propagator::eq_eh_t m_eq_eh; user_propagator::eq_eh_t m_diseq_eh; - user_propagator::created_eh_t m_created_eh; + user_propagator::created_eh_t m_created_eh; user_propagator::context_obj* m_api_context = nullptr; unsigned m_qhead = 0; @@ -76,6 +76,15 @@ namespace smt { literal_vector m_lits; enode_pair_vector m_eqs; stats m_stats; + expr_ref_vector m_var2expr; + unsigned_vector m_expr2var; + + expr* var2expr(theory_var v) { return m_var2expr.get(v); } + theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; } + void check_defined(expr* e) { + if (e->get_id() >= m_expr2var.size() || get_num_vars() <= m_expr2var[e->get_id()]) + throw default_exception("expression is not registered"); + } void force_push(); @@ -101,7 +110,7 @@ namespace smt { m_fresh_eh = fresh_eh; } - unsigned add_expr(expr* e); + void add_expr(expr* e); void register_final(user_propagator::final_eh_t& final_eh) { m_final_eh = final_eh; } void register_fixed(user_propagator::fixed_eh_t& fixed_eh) { m_fixed_eh = fixed_eh; } @@ -110,17 +119,17 @@ namespace smt { void register_created(user_propagator::created_eh_t& created_eh) { m_created_eh = created_eh; } bool has_fixed() const { return (bool)m_fixed_eh; } - - void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* lhs, unsigned const* rhs, expr* conseq) override; - unsigned register_cb(expr* e) override; + + void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override; + void register_cb(expr* e) override; void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits); theory * mk_fresh(context * new_ctx) override; bool internalize_atom(app* atom, bool gate_ctx) override; bool internalize_term(app* term) override; - void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) m_eq_eh(m_user_context, this, v1, v2); } - void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) m_diseq_eh(m_user_context, this, v1, v2); } + void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) m_eq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); } + void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) m_diseq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); } bool use_diseqs() const override { return ((bool)m_diseq_eh); } bool build_models() const override { return false; } final_check_status final_check_eh() override; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 6ed570297..a2909fd7b 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -108,8 +108,8 @@ public: m_tactic->user_propagate_register_diseq(diseq_eh); } - unsigned user_propagate_register_expr(expr* e) override { - return m_tactic->user_propagate_register_expr(e); + void user_propagate_register_expr(expr* e) override { + m_tactic->user_propagate_register_expr(e); } void user_propagate_register_created(user_propagator::created_eh_t& created_eh) override { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 26a69fd4a..c97fa670e 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -892,9 +892,8 @@ public: m_num_elim_apps = 0; } - unsigned user_propagate_register_expr(expr* e) override { + void user_propagate_register_expr(expr* e) override { m_nonvars.insert(e); - return 0; } void user_propagate_clear() override { diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index 607928f64..7f0d82f2e 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -78,7 +78,7 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result) override; void cleanup() override; - unsigned user_propagate_register_expr(expr* e) override; + void user_propagate_register_expr(expr* e) override; void user_propagate_clear() override; }; @@ -502,9 +502,8 @@ void reduce_args_tactic::cleanup() { m_imp->m_vars.append(vars); } -unsigned reduce_args_tactic::user_propagate_register_expr(expr* e) { +void reduce_args_tactic::user_propagate_register_expr(expr* e) { m_imp->m_vars.push_back(e); - return 0; } void reduce_args_tactic::user_propagate_clear() { diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 437c7f804..af8b24b2f 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -85,7 +85,7 @@ public: throw default_exception("tactic does not support user propagation"); } - unsigned user_propagate_register_expr(expr* e) override { return 0; } + void user_propagate_register_expr(expr* e) override { } virtual char const* name() const = 0; protected: diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index c5a9e6984..2d14a5eaa 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -190,9 +190,9 @@ public: m_t2->user_propagate_register_diseq(diseq_eh); } - unsigned user_propagate_register_expr(expr* e) override { + void user_propagate_register_expr(expr* e) override { m_t1->user_propagate_register_expr(e); - return m_t2->user_propagate_register_expr(e); + m_t2->user_propagate_register_expr(e); } void user_propagate_clear() override { @@ -848,7 +848,7 @@ public: void reset() override { m_t->reset(); } void set_logic(symbol const& l) override { m_t->set_logic(l); } void set_progress_callback(progress_callback * callback) override { m_t->set_progress_callback(callback); } - unsigned user_propagate_register_expr(expr* e) override { return m_t->user_propagate_register_expr(e); } + void user_propagate_register_expr(expr* e) override { m_t->user_propagate_register_expr(e); } void user_propagate_clear() override { m_t->user_propagate_clear(); } protected: diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 403df8af5..07270ffe6 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -8,8 +8,8 @@ namespace user_propagator { class callback { public: virtual ~callback() = default; - virtual void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr* conseq) = 0; - virtual unsigned register_cb(expr* e) = 0; + virtual void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr* conseq) = 0; + virtual void register_cb(expr* e) = 0; }; class context_obj { @@ -18,12 +18,12 @@ namespace user_propagator { }; typedef std::function final_eh_t; - typedef std::function fixed_eh_t; - typedef std::function eq_eh_t; + typedef std::function fixed_eh_t; + typedef std::function eq_eh_t; typedef std::function fresh_eh_t; typedef std::function push_eh_t; typedef std::function pop_eh_t; - typedef std::function created_eh_t; + typedef std::function created_eh_t; class plugin : public decl_plugin { @@ -77,7 +77,7 @@ namespace user_propagator { throw default_exception("user-propagators are only supported on the SMT solver"); } - virtual unsigned user_propagate_register_expr(expr* e) { + virtual void user_propagate_register_expr(expr* e) { throw default_exception("user-propagators are only supported on the SMT solver"); } From 7091b1c856e6f85c3b9c0fc9cdb010f2d8ae38e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:29:18 +0200 Subject: [PATCH 044/258] add additional regex operators to API --- src/api/api_ast.cpp | 12 +++++++++--- src/api/dotnet/Context.cs | 2 +- src/api/z3_api.h | 10 +++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 87e218d99..d5de6b5fb 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1224,15 +1224,21 @@ extern "C" { case OP_RE_PLUS: return Z3_OP_RE_PLUS; case OP_RE_STAR: return Z3_OP_RE_STAR; case OP_RE_OPTION: return Z3_OP_RE_OPTION; + case OP_RE_RANGE: return Z3_OP_RE_RANGE; case OP_RE_CONCAT: return Z3_OP_RE_CONCAT; case OP_RE_UNION: return Z3_OP_RE_UNION; case OP_RE_DIFF: return Z3_OP_RE_DIFF; - case OP_RE_POWER: return Z3_OP_RE_POWER; case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT; case OP_RE_LOOP: return Z3_OP_RE_LOOP; - case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET; - //case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_SET; + case OP_RE_POWER: return Z3_OP_RE_POWER; + case OP_RE_COMPLEMENT: return Z3_OP_RE_COMPLEMENT; case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET; + + case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET; + case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_CHAR_SET; + case OP_RE_OF_PRED: return Z3_OP_RE_OF_PRED; + case OP_RE_REVERSE: return Z3_OP_RE_REVERSE; + case OP_RE_DERIVATIVE: return Z3_OP_RE_DERIVATIVE; default: return Z3_OP_INTERNAL; } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 214411053..94b69d206 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2497,7 +2497,7 @@ namespace Microsoft.Z3 } /// - /// Check if the string s1 is lexicographically strictly less than s2. + /// Check if the string s1 is lexicographically less or equal to s2. /// public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2) { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 95c04ea17..d8c817933 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1220,13 +1220,17 @@ typedef enum { Z3_OP_RE_CONCAT, Z3_OP_RE_UNION, Z3_OP_RE_RANGE, + Z3_OP_RE_DIFF, + Z3_OP_RE_INTERSECT, Z3_OP_RE_LOOP, Z3_OP_RE_POWER, - Z3_OP_RE_INTERSECT, - Z3_OP_RE_DIFF, + Z3_OP_RE_COMPLEMENT, Z3_OP_RE_EMPTY_SET, Z3_OP_RE_FULL_SET, - Z3_OP_RE_COMPLEMENT, + Z3_OP_RE_FULL_CHAR_SET, + Z3_OP_RE_OF_PRED, + Z3_OP_RE_REVERSE, + Z3_OP_RE_DERIVATIVE, // char Z3_OP_CHAR_CONST, From 9a1a72867c99def51fdade411ebf2aa69dcdb797 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:29:38 +0200 Subject: [PATCH 045/258] Add str.<= and str.< to Java API --- src/api/java/Context.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index c6d928de2..e0df3797b 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2106,6 +2106,26 @@ public class Context implements AutoCloseable { return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } + /** + * Check if the string s1 is lexicographically strictly less than s2. + */ + + public BoolExpr MkStringLt(SeqSort s1, SeqSort s2) + { + checkContextMatch(s1, s2); + return new BoolExpr(this, Native.mkStrLt(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + } + + /** + * Check if the string s1 is lexicographically less or equal to s2. + */ + public BoolExpr MkStringLe(SeqSort s1, SeqSort s2) + { + checkContextMatch(s1, s2); + return new BoolExpr(this, Native.mkStrLe(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + } + + /** * Retrieve sequence of length one at index. */ From 91045d3e4ae4f88f3eb4dbd4ee8e6197d15123ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:29:57 +0200 Subject: [PATCH 046/258] two words --- src/ast/rewriter/th_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index bb29b53db..3bc9c4ce1 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -305,12 +305,12 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr * arg1 = ite->get_arg(1); expr * arg2 = ite->get_arg(2); - if (m().is_ite(arg1) && arg1->get_ref_count() == 1) // do not apply on shared terms, since it may blowup + if (m().is_ite(arg1) && arg1->get_ref_count() == 1) // do not apply on shared terms, since it may blow up todo.push_back(to_app(arg1)); else if (!m().is_value(arg1)) return false; - if (m().is_ite(arg2) && arg2->get_ref_count() == 1) // do not apply on shared terms, since it may blowup + if (m().is_ite(arg2) && arg2->get_ref_count() == 1) // do not apply on shared terms, since it may blow up todo.push_back(to_app(arg2)); else if (!m().is_value(arg2)) return false; From 10b611b3bad0136251ca58ec2128a9c40009ba6b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:30:52 +0200 Subject: [PATCH 047/258] fix #5850 --- src/sat/smt/pb_solver.cpp | 52 +++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 62e3c88fb..a80dca507 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -70,7 +70,7 @@ namespace pb { SASSERT(s().at_base_lvl()); if (p.lit() != sat::null_literal && value(p.lit()) == l_false) { TRACE("ba", tout << "pb: flip sign " << p << "\n";); - IF_VERBOSE(1, verbose_stream() << "sign is flipped " << p << "\n";); + IF_VERBOSE(2, verbose_stream() << "sign is flipped " << p << "\n";); return; } bool nullify = p.lit() != sat::null_literal && value(p.lit()) == l_true; @@ -110,22 +110,21 @@ namespace pb { } } else if (true_val >= p.k()) { - if (p.lit() != sat::null_literal) { - IF_VERBOSE(100, display(verbose_stream() << "assign true literal ", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "assign true literal ", p, true);); + if (p.lit() != sat::null_literal) s().assign_scoped(p.lit()); - } - remove_constraint(p, "is true"); + else + remove_constraint(p, "is true"); } else if (slack + true_val < p.k()) { if (p.lit() != sat::null_literal) { - IF_VERBOSE(100, display(verbose_stream() << "assign false literal ", p, true);); + IF_VERBOSE(3, display(verbose_stream() << "assign false literal ", p, true);); s().assign_scoped(~p.lit()); } else { - IF_VERBOSE(1, verbose_stream() << "unsat during simplification\n";); + IF_VERBOSE(1, verbose_stream() << "unsat during simplification\n"); s().set_conflict(sat::justification(0)); } - remove_constraint(p, "is false"); } else if (slack + true_val == p.k()) { literal_vector lits(p.literals()); @@ -133,14 +132,16 @@ namespace pb { remove_constraint(p, "is tight"); } else { + unsigned sz = p.size(); clear_watch(p); unsigned j = 0; for (unsigned i = 0; i < sz; ++i) { literal l = p.get_lit(i); if (value(l) == l_undef) { - if (i != j) p.swap(i, j); - ++j; + if (i != j) + p.swap(i, j); + ++j; } } sz = j; @@ -168,6 +169,7 @@ namespace pb { _bad_id = 11111111; SASSERT(p.well_formed()); m_simplify_change = true; + } } @@ -2036,7 +2038,7 @@ namespace pb { m_constraint_to_reinit.shrink(sz); } - void solver::simplify() { + void solver::simplify() { if (!s().at_base_lvl()) s().pop_to_base_level(); if (s().inconsistent()) @@ -2193,7 +2195,7 @@ namespace pb { } } - bool solver::set_root(literal l, literal r) { + bool solver::set_root(literal l, literal r) { if (s().is_assumption(l.var())) return false; reserve_roots(); @@ -2206,17 +2208,18 @@ namespace pb { } void solver::flush_roots() { - if (m_roots.empty()) return; + if (m_roots.empty()) + return; reserve_roots(); - // validate(); + DEBUG_CODE(validate();); m_constraint_removed = false; for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) flush_roots(*m_constraints[i]); for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) flush_roots(*m_learned[i]); cleanup_constraints(); - // validate(); - // validate_eliminated(); + DEBUG_CODE(validate();); + DEBUG_CODE(validate_eliminated();); } void solver::validate_eliminated() { @@ -2765,7 +2768,7 @@ namespace pb { ptr_vector::iterator it2 = it; ptr_vector::iterator end = cs.end(); for (; it != end; ++it) { - constraint& c = *(*it); + constraint& c = *(*it); if (c.was_removed()) { clear_watch(c); c.nullify_tracking_literal(*this); @@ -3228,9 +3231,6 @@ namespace pb { display(verbose_stream(), p, true);); return false; } - // if (value(alit) == l_true && lvl(l) == lvl(alit)) { - // std::cout << "same level " << alit << " " << l << "\n"; - // } } // the sum of elements not in r or alit add up to less than k. unsigned sum = 0; @@ -3425,19 +3425,11 @@ namespace pb { ++num_max_level; } } - if (m_overflow) { + if (m_overflow) return nullptr; - } - if (slack >= k) { -#if 0 - return active2constraint(); - active2pb(m_A); - std::cout << "not asserting\n"; - display(std::cout, m_A, true); -#endif + if (slack >= k) return nullptr; - } // produce asserting cardinality constraint literal_vector lits; From 4d184fe65d5afdb58611b9c537d597f59564c926 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:31:10 +0200 Subject: [PATCH 048/258] skip expensive equality rewriting of Booleans --- src/tactic/core/solve_eqs_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index a73fe88b6..8d4130a89 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -649,7 +649,7 @@ class solve_eqs_tactic : public tactic { for (unsigned i = 0; i < args.size(); ++i) { pr = nullptr; expr* arg = args.get(i), *lhs = nullptr, *rhs = nullptr; - if (m().is_eq(arg, lhs, rhs)) { + if (m().is_eq(arg, lhs, rhs) && !m().is_bool(lhs)) { if (trivial_solve1(lhs, rhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { insert_solution(g, idx, arg, var, def, pr); } From c25d710958ea6993df5870c93429a12eae886611 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:31:29 +0200 Subject: [PATCH 049/258] try out arch arm64 on the mac --- scripts/nightly.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 08b3501a0..69fedc00c 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,5 +1,6 @@ variables: ReleaseVersion: '4.8.15' + MacFlags: 'CXXFLAGS=-arch arm64 LINK_EXTRA_FLAGS=-arch arm64 SLINK_EXTRA_FLAGS=-arch arm64' stages: - stage: Build @@ -10,7 +11,7 @@ stages: pool: vmImage: "macOS-latest" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - script: $(MacFlags) python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - script: git clone https://github.com/z3prover/z3test z3test - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. From ff5d210e8168ba75b1058da3dac7c7a972d060f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:33:15 +0200 Subject: [PATCH 050/258] na --- src/api/java/Context.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index e0df3797b..466047c16 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2112,8 +2112,8 @@ public class Context implements AutoCloseable { public BoolExpr MkStringLt(SeqSort s1, SeqSort s2) { - checkContextMatch(s1, s2); - return new BoolExpr(this, Native.mkStrLt(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return new BoolExpr(this, Native.mkStrLt(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -2121,8 +2121,8 @@ public class Context implements AutoCloseable { */ public BoolExpr MkStringLe(SeqSort s1, SeqSort s2) { - checkContextMatch(s1, s2); - return new BoolExpr(this, Native.mkStrLe(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return new BoolExpr(this, Native.mkStrLe(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } From d0d4ab7955d7e5fe61c68da125fd20e3e3702278 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 10:33:29 +0200 Subject: [PATCH 051/258] #5820 --- src/muz/fp/horn_tactic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 6ffd0f745..560202ab3 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -241,7 +241,7 @@ class horn_tactic : public tactic { verify(q, g, result, mc, pc); } g->set(pc.get()); - g->set(mc.get()); + g->add(mc.get()); } void verify(expr* q, @@ -282,12 +282,11 @@ class horn_tactic : public tactic { } case l_false: { // goal is sat - mc = concat(g->mc(), mc.get()); g->reset(); if (produce_models) { model_ref md = m_ctx.get_model(); model_converter_ref mc2 = model2model_converter(md.get()); - mc = concat(mc.get(), mc2.get()); + mc = mc2.get(); TRACE("dl", mc->display(tout << *md << "\n");); } break; @@ -345,6 +344,7 @@ class horn_tactic : public tactic { g->assert_expr(fml); } g->set_prec(goal::UNDER_OVER); + mc = g->mc(); } void check_parameters() { From e800269cee9f49b9323b264969ff2ed9070947d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 13:05:53 +0200 Subject: [PATCH 052/258] na --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 69fedc00c..2bf85c562 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,6 +1,6 @@ variables: ReleaseVersion: '4.8.15' - MacFlags: 'CXXFLAGS=-arch arm64 LINK_EXTRA_FLAGS=-arch arm64 SLINK_EXTRA_FLAGS=-arch arm64' + MacFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64"' stages: - stage: Build From 14ee02183c043c95d077d3ea8413ecfda4b45c93 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 13:43:11 +0200 Subject: [PATCH 053/258] nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 2bf85c562..de647ee9a 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,6 +1,6 @@ variables: ReleaseVersion: '4.8.15' - MacFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64"' + MacFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64" CPPFLAGS="-arch arm64"' stages: - stage: Build From f66b4f088062fcda727fcc5081479191d3a3a456 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 15:32:41 +0200 Subject: [PATCH 054/258] fir #5856 --- src/util/zstring.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/zstring.cpp b/src/util/zstring.cpp index e73c4cd52..570510458 100644 --- a/src/util/zstring.cpp +++ b/src/util/zstring.cpp @@ -216,7 +216,7 @@ int zstring::indexofu(zstring const& other, unsigned offset) const { int zstring::last_indexof(zstring const& other) const { if (other.length() == 0) return length(); if (other.length() > length()) return -1; - for (unsigned last = length() - other.length(); last-- > 0; ) { + for (unsigned last = length() - other.length() + 1; last-- > 0; ) { bool suffix = true; for (unsigned j = 0; suffix && j < other.length(); ++j) { suffix = m_buffer[last + j] == other[j]; From b38b6daba36297e8a9268fc94af038400e58a51f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 15:33:13 +0200 Subject: [PATCH 055/258] add option to disable FPMATH --- scripts/mk_util.py | 4 ++++ scripts/nightly.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1e105b002..b2f86e6b3 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -114,6 +114,7 @@ ALWAYS_DYNAMIC_BASE=False FPMATH="Default" FPMATH_FLAGS="-mfpmath=sse -msse -msse2" +FPMATH_ENABLED=getenv("FPMATH_ENABLED", "True") def check_output(cmd): @@ -278,6 +279,9 @@ def test_gmp(cc): def test_fpmath(cc): global FPMATH_FLAGS + if FPMATH_ENABLED == "False": + FPMATH_FLAGS="" + return "Disabled" if is_verbose(): print("Testing floating point support...") t = TempFile('tstsse.cpp') diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index de647ee9a..652f88f1c 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,6 +1,6 @@ variables: ReleaseVersion: '4.8.15' - MacFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64" CPPFLAGS="-arch arm64"' + MacFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64" FPMATH_ENABLED=False' stages: - stage: Build From 1e463955c20eba19026941b439e295c4e74e0375 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 09:09:28 -0800 Subject: [PATCH 056/258] #4889 avoid double internalize of bvle Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index ba0c2933c..6c6904c39 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -993,7 +993,9 @@ namespace smt { process_args(n); expr_ref_vector arg1_bits(m), arg2_bits(m); get_arg_bits(n, 0, arg1_bits); - get_arg_bits(n, 1, arg2_bits); + get_arg_bits(n, 1, arg2_bits); + if (ctx.b_internalized(n)) + return; expr_ref le(m); if (Signed) m_bb.mk_sle(arg1_bits.size(), arg1_bits.data(), arg2_bits.data(), le); From 5c2624950baa5a69bb7ccce20b59486e7692ea6c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 09:52:42 -0800 Subject: [PATCH 057/258] #5849 --- src/tactic/bv/bit_blaster_model_converter.cpp | 5 ++--- src/tactic/bv/bv1_blaster_tactic.cpp | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 061a51220..fe3294e4c 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -21,6 +21,7 @@ Notes: #include "tactic/model_converter.h" #include "ast/bv_decl_plugin.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_pp.h" #include "ast/ast_util.h" /** @@ -40,9 +41,7 @@ struct bit_blaster_model_converter : public model_converter { obj_map const & const2bits, ptr_vector const& newbits): m_vars(m), m_bits(m), m_newbits(m) { - for (auto const& kv : const2bits) { - func_decl * v = kv.m_key; - expr * bits = kv.m_value; + for (auto const& [v, bits] : const2bits) { SASSERT(!TO_BOOL || is_app_of(bits, m.get_family_id("bv"), OP_MKBV)); SASSERT(TO_BOOL || is_app_of(bits, m.get_family_id("bv"), OP_CONCAT)); m_vars.push_back(v); diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index 0fc38f2db..d3f19d1bd 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -37,7 +37,7 @@ class bv1_blaster_tactic : public tactic { bv_util m_util; obj_map m_const2bits; ptr_vector m_newbits; - expr_ref_vector m_saved; + ast_ref_vector m_saved; expr_ref m_bit1; expr_ref m_bit0; @@ -108,9 +108,11 @@ class bv1_blaster_tactic : public tactic { for (unsigned i = 0; i < bv_size; i++) { bits.push_back(m().mk_fresh_const(nullptr, b)); m_newbits.push_back(to_app(bits.back())->get_decl()); + m_saved.push_back(m_newbits.back()); } r = butil().mk_concat(bits.size(), bits.data()); m_saved.push_back(r); + m_saved.push_back(f); m_const2bits.insert(f, r); result = r; } From b84361805117c7fbe61c72c93253e75822d8c4c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 13:54:15 -0800 Subject: [PATCH 058/258] fix #5798 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_array.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index ab1673a9d..2d166c5f6 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -240,12 +240,16 @@ namespace smt { bool theory_array::internalize_term_core(app * n) { TRACE("array_bug", tout << mk_bounded_pp(n, m) << "\n";); unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - ctx.internalize(n->get_arg(i), false); - if (ctx.e_internalized(n)) { + for (expr* arg : *n) + ctx.internalize(arg, false); + // force merge-tf by re-internalizing expression. + for (expr* arg : *n) + if (m.is_bool(arg)) + ctx.internalize(arg, false); + if (ctx.e_internalized(n)) return false; - } - enode * e = ctx.mk_enode(n, false, false, true); + + enode * e = ctx.mk_enode(n, false, false, true); if (!is_attached_to_var(e)) mk_var(e); From cfe9846f0cb75cdc76617b8f9643dbea50eca888 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 13:59:42 -0800 Subject: [PATCH 059/258] multi Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 652f88f1c..2f4f4ba6a 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,6 +1,6 @@ variables: ReleaseVersion: '4.8.15' - MacFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64" FPMATH_ENABLED=False' + MacFlags: 'CXXFLAGS="-arch arm64 x86_64" LINK_EXTRA_FLAGS="-arch arm64 x86_64" SLINK_EXTRA_FLAGS="-arch arm64 x86_64" FPMATH_ENABLED=False' stages: - stage: Build From c47e5aff60ccc90df661800046ac4f52570c5be5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Feb 2022 14:03:13 -0800 Subject: [PATCH 060/258] multi Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 2f4f4ba6a..9a410c311 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,6 +1,6 @@ variables: ReleaseVersion: '4.8.15' - MacFlags: 'CXXFLAGS="-arch arm64 x86_64" LINK_EXTRA_FLAGS="-arch arm64 x86_64" SLINK_EXTRA_FLAGS="-arch arm64 x86_64" FPMATH_ENABLED=False' + MacFlags: 'CXXFLAGS="-archs arm64 x86_64" LINK_EXTRA_FLAGS="-archs arm64 x86_64" SLINK_EXTRA_FLAGS="-archs arm64 x86_64" FPMATH_ENABLED=False' stages: - stage: Build From 456b8ee68294acfb16eb624ff01f20b1edc9d547 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Feb 2022 04:18:05 -0800 Subject: [PATCH 061/258] nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 9a410c311..4ed072d7c 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,6 +1,6 @@ variables: ReleaseVersion: '4.8.15' - MacFlags: 'CXXFLAGS="-archs arm64 x86_64" LINK_EXTRA_FLAGS="-archs arm64 x86_64" SLINK_EXTRA_FLAGS="-archs arm64 x86_64" FPMATH_ENABLED=False' + MacFlags: 'CXXFLAGS="-arch arm64 -arch x86_64" LINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" SLINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" FPMATH_ENABLED=False' stages: - stage: Build From e8d4804dbb726b8b13cc996cc33bd57d6acc893a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Feb 2022 04:33:52 -0800 Subject: [PATCH 062/258] Revert "use horn_subsume_model_converter in coi filter (#5844)" (#5859) This reverts commit 09da87dc85560312fe5c6dbfa4929e82a420f8e8. --- src/muz/transforms/dl_mk_coi_filter.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index d3f6555aa..841ab4637 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -139,12 +139,24 @@ namespace datalog { res = nullptr; } if (res && m_context.get_model_converter()) { - horn_subsume_model_converter* mc0 = alloc(horn_subsume_model_converter, m); + generic_model_converter* mc0 = alloc(generic_model_converter, m, "dl_coi"); for (func_decl* f : pruned_preds) { const rule_vector& rules = source.get_predicate_rules(f); + expr_ref_vector fmls(m); for (rule * r : rules) { - datalog::del_rule(mc0, *r, false); + app* head = r->get_head(); + expr_ref_vector conj(m); + for (unsigned j = 0; j < head->get_num_args(); ++j) { + expr* arg = head->get_arg(j); + if (!is_var(arg)) { + conj.push_back(m.mk_eq(m.mk_var(j, arg->get_sort()), arg)); + } + } + fmls.push_back(mk_and(conj)); } + expr_ref fml(m); + fml = m.mk_or(fmls.size(), fmls.data()); + mc0->add(f, fml); } m_context.add_model_converter(mc0); } From 061e94d723422b240e23743c8ef3f99739f1ac23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Feb 2022 17:45:00 -0800 Subject: [PATCH 063/258] #5858 COI model converter has to use constraints from the body and work in disjunctive mode. It needs a pre-condition that the body does not depend on other rules, in the case that it is used in a different pre-processing step for in-lining. The in-lined occurrence of the predicate has to correspond to the model construction version. --- src/muz/transforms/dl_mk_coi_filter.cpp | 55 +++++++++++++-------- src/tactic/horn_subsume_model_converter.cpp | 17 +++---- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 841ab4637..389f0abab 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -118,7 +118,7 @@ namespace datalog { } rule_set * mk_coi_filter::top_down(rule_set const & source) { - func_decl_set pruned_preds; + func_decl_set pruned_preds, seen; dataflow_engine engine(source.get_manager(), source); engine.run_top_down(); scoped_ptr res = alloc(rule_set, m_context); @@ -126,37 +126,50 @@ namespace datalog { for (rule * r : source) { func_decl * pred = r->get_decl(); - if (engine.get_fact(pred).is_reachable()) { - res->add_rule(r); - } + bool should_keep = false; + if (seen.contains(pred)) + continue; + seen.insert(pred); + if (engine.get_fact(pred).is_reachable()) + should_keep = true; else if (m_context.get_model_converter()) { - pruned_preds.insert(pred); + bool should_keep = false; + for (rule* pr : source.get_predicate_rules(pred)) + for (unsigned i = 0; i < pr->get_uninterpreted_tail_size(); ++i) + should_keep |= pr->get_tail(i)->get_decl() != pred; } + else + continue; + + if (should_keep) + for (rule* pr : source.get_predicate_rules(pred)) + res->add_rule(pr); + else + pruned_preds.insert(pred); } if (res->get_num_rules() == source.get_num_rules()) { TRACE("dl", tout << "No transformation\n";); res = nullptr; } - if (res && m_context.get_model_converter()) { - generic_model_converter* mc0 = alloc(generic_model_converter, m, "dl_coi"); - for (func_decl* f : pruned_preds) { + if (res && m_context.get_model_converter() && !pruned_preds.empty()) { + auto* mc0 = alloc(generic_model_converter, m, "dl_coi"); + horn_subsume_model_converter hmc(m); + + for (func_decl* f : pruned_preds) { const rule_vector& rules = source.get_predicate_rules(f); expr_ref_vector fmls(m); - for (rule * r : rules) { - app* head = r->get_head(); - expr_ref_vector conj(m); - for (unsigned j = 0; j < head->get_num_args(); ++j) { - expr* arg = head->get_arg(j); - if (!is_var(arg)) { - conj.push_back(m.mk_eq(m.mk_var(j, arg->get_sort()), arg)); - } - } - fmls.push_back(mk_and(conj)); + for (rule* r : rules) { + expr_ref_vector constraints(m); + expr_ref body_res(m); + func_decl_ref pred(m); + for (unsigned i = r->get_uninterpreted_tail_size(); i < r->get_tail_size(); ++i) + constraints.push_back(r->get_tail(i)); + expr_ref body = mk_and(constraints); + VERIFY(hmc.mk_horn(r->get_head(), body, pred, body_res)); + fmls.push_back(body_res); } - expr_ref fml(m); - fml = m.mk_or(fmls.size(), fmls.data()); - mc0->add(f, fml); + mc0->add(f, mk_or(fmls)); } m_context.add_model_converter(mc0); } diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp index 79b9a038f..979359a46 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/tactic/horn_subsume_model_converter.cpp @@ -80,8 +80,8 @@ bool horn_subsume_model_converter::mk_horn( if (w >= subst.size()) { subst.resize(w+1); } - if (subst[w].get()) { - conjs.push_back(m.mk_eq(v, subst[w].get())); + if (subst.get(w)) { + conjs.push_back(m.mk_eq(v, subst.get(w))); } else { subst[w] = v; @@ -92,11 +92,11 @@ bool horn_subsume_model_converter::mk_horn( } } expr_ref body_expr(m); - body_expr = m.mk_and(conjs.size(), conjs.data()); + body_expr = m.mk_and(conjs); // substitute variables directly. if (!subst.empty()) { - body_expr = vs(body_expr, subst.size(), subst.data()); + body_expr = vs(body_expr, subst); } if (fv.empty()) { @@ -174,17 +174,16 @@ void horn_subsume_model_converter::operator()(model_ref& mr) { func_decl_ref pred(m); expr_ref body_res(m); for (unsigned i = 0; i < m_delay_head.size(); ++i) { - VERIFY(mk_horn(m_delay_head[i].get(), m_delay_body[i].get(), pred, body_res)); + VERIFY(mk_horn(m_delay_head.get(i), m_delay_body.get(i), pred, body_res)); insert(pred.get(), body_res.get()); } m_delay_head.reset(); m_delay_body.reset(); TRACE("mc", tout << m_funcs.size() << "\n"; model_smt2_pp(tout, m, *mr, 0);); - for (unsigned i = m_funcs.size(); i > 0; ) { - --i; - func_decl* h = m_funcs[i].get(); - expr_ref body(m_bodies[i].get(), m); + for (unsigned i = m_funcs.size(); i-- > 0; ) { + func_decl* h = m_funcs.get(i); + expr_ref body(m_bodies.get(i), m); unsigned arity = h->get_arity(); add_default_false_interpretation(body, mr); SASSERT(m.is_bool(body)); From d06c51d51738f56ef754a567e6e474bd52afc4d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Feb 2022 17:46:54 -0800 Subject: [PATCH 064/258] na Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_coi_filter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 389f0abab..f78914b1c 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -133,7 +133,6 @@ namespace datalog { if (engine.get_fact(pred).is_reachable()) should_keep = true; else if (m_context.get_model_converter()) { - bool should_keep = false; for (rule* pr : source.get_predicate_rules(pred)) for (unsigned i = 0; i < pr->get_uninterpreted_tail_size(); ++i) should_keep |= pr->get_tail(i)->get_decl() != pred; From ea0876b6d6ebe3f97171e88e9d06aaf42bdf5b45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Feb 2022 18:05:29 -0800 Subject: [PATCH 065/258] add lambda definitions during ast translation #5820 Signed-off-by: Nikolaj Bjorner --- src/ast/ast_translation.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index c4e32a303..781593b38 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -170,12 +170,20 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) { new_fi.set_injective(fi->is_injective()); new_fi.set_skolem(fi->is_skolem()); new_fi.set_idempotent(fi->is_idempotent()); + new_fi.set_lambda(fi->is_lambda()); new_f = m_to_manager.mk_func_decl(f->get_name(), f->get_arity(), new_domain, new_range, new_fi); + + if (new_fi.is_lambda()) { + quantifier* q = from().is_lambda_def(f); + ast_translation tr(from(), to()); + quantifier* new_q = tr(q); + to().add_lambda_def(new_f, new_q); + } } TRACE("ast_translation", tout << f->get_name() << " "; if (fi) tout << *fi; tout << "\n"; From 11030fc81dce9cf409cedc90d08786fca38594a8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Feb 2022 18:56:49 -0800 Subject: [PATCH 066/258] disable unsound mk_seq_butlast Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 18af6a239..b5f0e1475 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -943,7 +943,7 @@ expr_ref seq_rewriter::mk_seq_butlast(expr* t) { expr_ref result(m()); expr* s, * j, * k; rational v; - if (str().is_extract(t, s, j, k) && m_autil.is_numeral(j, v) && v.is_zero()) { + if (false && str().is_extract(t, s, j, k) && m_autil.is_numeral(j, v) && v.is_zero()) { expr_ref_vector k_min_1(m()); k_min_1.push_back(k); k_min_1.push_back(minus_one()); From c2f1bdc099753b82abe36f04dee95b6b034db7e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Feb 2022 08:05:05 -0800 Subject: [PATCH 067/258] fix #5862 --- src/muz/transforms/dl_mk_coi_filter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index f78914b1c..ba85e569a 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -133,9 +133,11 @@ namespace datalog { if (engine.get_fact(pred).is_reachable()) should_keep = true; else if (m_context.get_model_converter()) { - for (rule* pr : source.get_predicate_rules(pred)) + for (rule* pr : source.get_predicate_rules(pred)) for (unsigned i = 0; i < pr->get_uninterpreted_tail_size(); ++i) - should_keep |= pr->get_tail(i)->get_decl() != pred; + if (pr->get_tail(i)->get_decl() != pred) + // don't try to eliminate across predicates + return nullptr; } else continue; From 6af170b058697e5fb18808728bb94de16c2027da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Feb 2022 11:26:09 -0800 Subject: [PATCH 068/258] fix #5861 sigh --- src/smt/theory_array_full.cpp | 37 ++--------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index baf2df503..1a793a116 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -745,8 +745,8 @@ namespace smt { // // expr_ref_vector args1(m), args2(m); - args1.push_back(store_app->get_arg(0)); - args2.push_back(store_app); + args1.push_back(store_app); + args2.push_back(store_app->get_arg(0)); for (unsigned i = 1; i + 1 < num_args; ++i) { expr* arg = store_app->get_arg(i); @@ -762,39 +762,6 @@ namespace smt { ctx.internalize(def2, false); is_new = try_assign_eq(def1, sel1) || try_assign_eq(def2, sel2); return is_new; - - -#if 0 - // - // This is incorrect, issue #5593. - // - - // let A = store(B, i, v) - // - // Add: - // default(A) = ite(epsilon1 = i, v, default(B)) - // A[diag(i)] = B[diag(i)] - // - expr_ref_vector eqs(m); - expr_ref_vector args1(m), args2(m); - args1.push_back(store_app->get_arg(0)); - args2.push_back(store_app); - - for (unsigned i = 1; i + 1 < num_args; ++i) { - expr* arg = store_app->get_arg(i); - sort* srt = arg->get_sort(); - auto ep = mk_epsilon(srt); - eqs.push_back(m.mk_eq(ep.first, arg)); - args1.push_back(m.mk_app(ep.second, arg)); - args2.push_back(m.mk_app(ep.second, arg)); - } - expr_ref eq(mk_and(eqs), m); - def2 = m.mk_ite(eq, store_app->get_arg(num_args-1), def2); - app_ref sel1(m), sel2(m); - sel1 = mk_select(args1); - sel2 = mk_select(args2); - is_new = try_assign_eq(sel1, sel2); -#endif } ctx.internalize(def1, false); From 6be0a66b3898a248313bae792ce0df760e8fd85a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Feb 2022 13:00:20 -0800 Subject: [PATCH 069/258] fix #5863 --- src/muz/base/dl_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 5114cb1c3..eb832f93e 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -286,7 +286,7 @@ namespace datalog { ast_manager& m = mc->get_manager(); expr_ref_vector body(m); if (unreachable) { - body.push_back(m.mk_false()); + body.push_back(m.mk_true()); } else { for (unsigned i = 0; i < r.get_tail_size(); ++i) { From dc110f10a4ec887707ff5579870eb1512a2ec10b Mon Sep 17 00:00:00 2001 From: Emma Jane Bonestell Date: Wed, 23 Feb 2022 05:36:46 -0600 Subject: [PATCH 070/258] Update mk_util.py (#5864) Fix dynamic -lib opam builds on MSYS2 --- scripts/mk_util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b2f86e6b3..ce34ac7eb 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2080,7 +2080,7 @@ class MLComponent(Component): out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxa')))) out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxs')))) out.write(' %s' % ((os.path.join(self.sub_dir, 'dllz3ml')))) - if is_windows() or is_cygwin_mingw(): + if is_windows() or is_cygwin_mingw() or is_msys2(): out.write('.dll') else: out.write('.so') # .so also on OSX! @@ -2628,7 +2628,7 @@ def mk_config(): SLIBFLAGS = '%s -m32' % SLIBFLAGS if TRACE or DEBUG_MODE: CPPFLAGS = '%s -D_TRACE' % CPPFLAGS - if is_cygwin_mingw(): + if is_cygwin_mingw() or is_msys2(): # when cross-compiling with MinGW, we need to statically link its standard libraries # and to make it create an import library. SLIBEXTRAFLAGS = '%s -static-libgcc -static-libstdc++ -Wl,--out-implib,libz3.dll.a' % SLIBEXTRAFLAGS From 7b4f1ed530b6c644d1cbd49aee3c9fca295151e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Feb 2022 04:49:33 -0800 Subject: [PATCH 071/258] missing initialization of m_user_propagator, disable unsound in-processing in pb_solver Signed-off-by: Nikolaj Bjorner --- src/sat/smt/pb_solver.cpp | 9 +++++++-- src/smt/smt_context.cpp | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index a80dca507..8340543ec 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -2637,6 +2637,10 @@ namespace pb { * add ~root(~l) to c, k <- k + 1 */ void solver::unit_strengthen() { + return; + + // TODO - this is unsound exposed by 4_21_21_-1.txt + sat::big big(s().m_rand); big.init(s(), true); for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) @@ -2646,7 +2650,8 @@ namespace pb { } void solver::unit_strengthen(sat::big& big, constraint& p) { - if (p.lit() != sat::null_literal) return; + if (p.lit() != sat::null_literal) + return; unsigned sz = p.size(); for (unsigned i = 0; i < sz; ++i) { literal u = p.get_lit(i); @@ -2694,8 +2699,8 @@ namespace pb { } } ++m_stats.m_num_big_strengthenings; + constraint* c = add_pb_ge(sat::null_literal, wlits, b, p.learned()); p.set_removed(); - add_pb_ge(sat::null_literal, wlits, b, p.learned()); return; } } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 735da24eb..186d03dc3 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -211,6 +211,7 @@ namespace smt { new_ctx->m_is_auxiliary = true; new_ctx->set_logic(l == nullptr ? m_setup.get_logic() : *l); copy_plugins(*this, *new_ctx); + new_ctx->copy_user_propagator(*this); return new_ctx; } From f2e712b0d6bbb19251020208c7fd31a74c0d232f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Feb 2022 08:45:22 -0800 Subject: [PATCH 072/258] throttle is_compatible to check variables at most once Signed-off-by: Nikolaj Bjorner --- src/tactic/core/solve_eqs_tactic.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 8d4130a89..30e4a8c4b 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -65,7 +65,8 @@ class solve_eqs_tactic : public tactic { m_a_util(m), m_num_steps(0), m_num_eliminated_vars(0), - m_marked_candidates(m) { + m_marked_candidates(m), + m_var_trail(m) { updt_params(p); if (m_r == nullptr) m_r = mk_default_expr_replacer(m, true); @@ -524,7 +525,14 @@ class solve_eqs_tactic : public tactic { } } + expr_mark m_compatible_tried; + expr_ref_vector m_var_trail; + bool is_compatible(goal const& g, unsigned idx, vector const & path, expr* v, expr* eq) { + if (m_compatible_tried.is_marked(v)) + return false; + m_compatible_tried.mark(v); + m_var_trail.push_back(v); expr_mark occ; svector cache; mark_occurs(occ, g, v); @@ -649,7 +657,7 @@ class solve_eqs_tactic : public tactic { for (unsigned i = 0; i < args.size(); ++i) { pr = nullptr; expr* arg = args.get(i), *lhs = nullptr, *rhs = nullptr; - if (m().is_eq(arg, lhs, rhs) && !m().is_bool(lhs)) { + if (m().is_eq(arg, lhs, rhs) && !m().is_bool(lhs)) { if (trivial_solve1(lhs, rhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { insert_solution(g, idx, arg, var, def, pr); } From 30a2f2fd9d696ebd710e90dd7803652f42f806cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Feb 2022 07:56:36 -0800 Subject: [PATCH 073/258] initial stab at NativeContext --- src/api/dotnet/CMakeLists.txt | 1 + src/api/dotnet/NativeContext.cs | 104 ++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 src/api/dotnet/NativeContext.cs diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index bab8ac982..5c722c828 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -85,6 +85,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE ListSort.cs Log.cs Model.cs + NativeContext.cs Optimize.cs ParamDescrs.cs Params.cs diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs new file mode 100644 index 000000000..57f3f96de --- /dev/null +++ b/src/api/dotnet/NativeContext.cs @@ -0,0 +1,104 @@ +using System; +using System.Diagnostics; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Linq; + +namespace Microsoft.Z3 +{ + using Z3_config = System.IntPtr; + using Z3_context = System.IntPtr; + using Z3_ast = System.IntPtr; + using Z3_app = System.IntPtr; + using Z3_sort = System.IntPtr; + using Z3_func_decl = System.IntPtr; + using Z3_pattern = System.IntPtr; + using Z3_model = System.IntPtr; + using Z3_literals = System.IntPtr; + using Z3_constructor = System.IntPtr; + using Z3_constructor_list = System.IntPtr; + using Z3_solver = System.IntPtr; + using Z3_solver_callback = System.IntPtr; + using Z3_goal = System.IntPtr; + using Z3_tactic = System.IntPtr; + using Z3_params = System.IntPtr; + using Z3_probe = System.IntPtr; + using Z3_stats = System.IntPtr; + using Z3_ast_vector = System.IntPtr; + using Z3_ast_map = System.IntPtr; + using Z3_apply_result = System.IntPtr; + using Z3_func_interp = System.IntPtr; + using Z3_func_entry = System.IntPtr; + using Z3_fixedpoint = System.IntPtr; + using Z3_optimize = System.IntPtr; + using Z3_param_descrs = System.IntPtr; + using Z3_rcf_num = System.IntPtr; + + /// + /// The main interaction with Z3 happens via the Context. + /// NativeContext allows for efficient wrapper-reduced interaction with Z3 + /// expressions. + /// + + public class NativeContext { + + #region Arithmetic + /// + /// Create an expression representing t[0] + t[1] + .... + /// + + public Z3_ast MkAdd(params Z3_ast[] t) + { + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != IntPtr.Zero)); + return Native.Z3_mk_add(nCtx, (uint)t.Length, t); + } + + #endregion + + #region Options + /// + /// Selects the format used for pretty-printing expressions. + /// + /// + /// The default mode for pretty printing expressions is to produce + /// SMT-LIB style output where common subexpressions are printed + /// at each occurrence. The mode is called Z3_PRINT_SMTLIB_FULL. + /// To print shared common subexpressions only once, + /// use the Z3_PRINT_LOW_LEVEL mode. + /// To print in way that conforms to SMT-LIB standards and uses let + /// expressions to share common sub-expressions use Z3_PRINT_SMTLIB_COMPLIANT. + /// + /// + /// + /// + /// + public Z3_ast_print_mode PrintMode + { + set { Native.Z3_set_ast_print_mode(nCtx, (uint)value); } + } + #endregion + + + #region Internal + internal IntPtr m_ctx = IntPtr.Zero; + internal Native.Z3_error_handler m_n_err_handler = null; + internal IntPtr nCtx { get { return m_ctx; } } + + internal void NativeErrorHandler(IntPtr ctx, Z3_error_code errorCode) + { + // Do-nothing error handler. The wrappers in Z3.Native will throw exceptions upon errors. + } + + internal void InitContext() + { + PrintMode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT; + m_n_err_handler = new Native.Z3_error_handler(NativeErrorHandler); // keep reference so it doesn't get collected. + Native.Z3_set_error_handler(m_ctx, m_n_err_handler); + GC.SuppressFinalize(this); + } + + #endregion + +} +} \ No newline at end of file From 7f149a36d7da605835ae79d1dab64e2c99cf34b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Feb 2022 08:03:46 -0800 Subject: [PATCH 074/258] refining model update rules for del_rule #5865 #5866 --- src/muz/base/dl_util.cpp | 18 ++++++++++++------ src/muz/base/dl_util.h | 2 +- src/muz/transforms/dl_mk_rule_inliner.cpp | 12 ++++++------ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index eb832f93e..03a8f1c99 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -281,14 +281,19 @@ namespace datalog { return get_max_var(has_var); } - void del_rule(horn_subsume_model_converter* mc, rule& r, bool unreachable) { + void del_rule(horn_subsume_model_converter* mc, rule& r, lbool unreachable) { if (mc) { ast_manager& m = mc->get_manager(); expr_ref_vector body(m); - if (unreachable) { + TRACE("dl", tout << "unreachable: " << unreachable << " " << r.get_decl()->get_name() << "\n"); + switch (unreachable) { + case l_true: body.push_back(m.mk_true()); - } - else { + break; + case l_false: + body.push_back(m.mk_false()); + break; + default: for (unsigned i = 0; i < r.get_tail_size(); ++i) { if (r.is_neg_tail(i)) { body.push_back(m.mk_not(r.get_tail(i))); @@ -297,11 +302,12 @@ namespace datalog { body.push_back(r.get_tail(i)); } } + break; } - TRACE("dl_dr", + TRACE("dl", tout << mk_pp(r.get_head(), m) << " :- \n"; for (unsigned i = 0; i < body.size(); ++i) { - tout << mk_pp(body[i].get(), m) << "\n"; + tout << mk_pp(body.get(i), m) << "\n"; }); mc->insert(r.get_head(), body.size(), body.data()); diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 1b69a2733..565b58c84 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -353,7 +353,7 @@ namespace datalog { unsigned get_max_rule_var(const rule& r); }; - void del_rule(horn_subsume_model_converter* mc, rule& r, bool unreachable); + void del_rule(horn_subsume_model_converter* mc, rule& r, lbool unreachable); void resolve_rule(rule_manager& rm, replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 1d4f05155..7b22b4133 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -410,7 +410,7 @@ namespace datalog { TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; ); for (rule * r : m_inlined_rules) { - datalog::del_rule(m_mc, *r, false); + datalog::del_rule(m_mc, *r, l_undef); } } @@ -449,7 +449,7 @@ namespace datalog { } } if (modified) { - datalog::del_rule(m_mc, *r0, true); + datalog::del_rule(m_mc, *r0, l_false); } return modified; @@ -473,7 +473,7 @@ namespace datalog { if (something_done && m_mc) { for (rule* r : orig) { if (inlining_allowed(orig, r->get_decl())) { - datalog::del_rule(m_mc, *r, true); + datalog::del_rule(m_mc, *r, l_undef); } } } @@ -558,7 +558,7 @@ namespace datalog { // nothing unifies with the tail atom, therefore the rule is unsatisfiable // (we can say this because relation pred doesn't have any ground facts either) res = nullptr; - datalog::del_rule(m_mc, *r, false); + datalog::del_rule(m_mc, *r, l_false); return true; } if (!is_oriented_rewriter(inlining_candidate, strat)) { @@ -568,7 +568,7 @@ namespace datalog { goto process_next_tail; } if (!try_to_inline_rule(*r, *inlining_candidate, ti, res)) { - datalog::del_rule(m_mc, *r, false); + datalog::del_rule(m_mc, *r, l_false); res = nullptr; } return true; @@ -801,7 +801,7 @@ namespace datalog { if (num_tail_unifiers == 1) { TRACE("dl", tout << "setting invalid: " << j << "\n";); valid.set(j, false); - datalog::del_rule(m_mc, *r2, true); + datalog::del_rule(m_mc, *r2, l_true); del_rule(r2, j); } From 689e2d41de8776b2af3be8d78ba5b15c86ff531e Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 25 Feb 2022 14:32:20 +0000 Subject: [PATCH 075/258] remove a bunch of unneeded memory allocations --- scripts/mk_genfile_common.py | 2 +- src/ast/ast.cpp | 6 +-- src/ast/ast.h | 4 +- src/util/gparams.cpp | 20 +++++----- src/util/gparams.h | 4 +- src/util/scoped_timer.cpp | 75 +++++++++++++++--------------------- src/util/scoped_timer.h | 5 ++- 7 files changed, 52 insertions(+), 64 deletions(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index ef73e5f3f..f4b54cba0 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -644,7 +644,7 @@ def mk_gparams_register_modules_internal(h_files_full_path, path): for code in cmds: fout.write('{ param_descrs d; %s(d); gparams::register_global(d); }\n' % code) for (mod, code) in mod_cmds: - fout.write('{ std::function f = []() { auto* d = alloc(param_descrs); %s(*d); return d; }; gparams::register_module("%s", f); }\n' % (code, mod)) + fout.write('{ auto f = []() { auto* d = alloc(param_descrs); %s(*d); return d; }; gparams::register_module("%s", f); }\n' % (code, mod)) for (mod, descr) in mod_descrs: fout.write('gparams::register_module_descr("%s", "%s");\n' % (mod, descr)) fout.write('}\n') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 2472e9efd..23ad23329 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1759,13 +1759,13 @@ ast * ast_manager::register_node_core(ast * n) { switch (n->get_kind()) { case AST_SORT: if (to_sort(n)->m_info != nullptr) { - to_sort(n)->m_info = alloc(sort_info, *(to_sort(n)->get_info())); + to_sort(n)->m_info = alloc(sort_info, std::move(*(to_sort(n)->get_info()))); to_sort(n)->m_info->init_eh(*this); } break; case AST_FUNC_DECL: if (to_func_decl(n)->m_info != nullptr) { - to_func_decl(n)->m_info = alloc(func_decl_info, *(to_func_decl(n)->get_info())); + to_func_decl(n)->m_info = alloc(func_decl_info, std::move(*(to_func_decl(n)->get_info()))); to_func_decl(n)->m_info->init_eh(*this); } inc_array_ref(to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain()); @@ -1993,7 +1993,7 @@ sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * c return s; } decl_info dinfo(s->get_family_id(), s->get_decl_kind(), ps.size(), ps.data(), s->private_parameters()); - sort_info sinfo(dinfo, s->get_num_elements()); + sort_info sinfo(std::move(dinfo), s->get_num_elements()); return mk_sort(s->get_name(), &sinfo); } diff --git a/src/ast/ast.h b/src/ast/ast.h index 13898c2a6..3cb90193f 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -367,8 +367,8 @@ public: decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) { } - sort_info(decl_info const& di, sort_size const& num_elements) : - decl_info(di), m_num_elements(num_elements) {} + sort_info(decl_info && di, sort_size const& num_elements) : + decl_info(std::move(di)), m_num_elements(num_elements) {} bool is_infinite() const { return m_num_elements.is_infinite(); } bool is_very_big() const { return m_num_elements.is_very_big(); } diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 0c679e388..25504eddd 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -86,13 +86,13 @@ static char const * get_new_param_name(std::string const & p) { template class smap : public map {}; -typedef std::function lazy_descrs_t; +typedef param_descrs* (*lazy_descrs_t)(void); class lazy_param_descrs { param_descrs* m_descrs; - ptr_vector m_mk; + svector m_mk; - void apply(lazy_descrs_t& f) { + void apply(lazy_descrs_t f) { param_descrs* d = f(); if (m_descrs) { m_descrs->copy(*d); @@ -104,18 +104,16 @@ class lazy_param_descrs { } void reset_mk() { - for (auto* f : m_mk) dealloc(f); m_mk.reset(); } public: - lazy_param_descrs(lazy_descrs_t& f): m_descrs(nullptr) { + lazy_param_descrs(lazy_descrs_t f): m_descrs(nullptr) { append(f); } ~lazy_param_descrs() { - dealloc(m_descrs); - reset_mk(); + dealloc(m_descrs); } param_descrs* deref() { @@ -124,8 +122,8 @@ public: return m_descrs; } - void append(lazy_descrs_t& f) { - m_mk.push_back(alloc(lazy_descrs_t, f)); + void append(lazy_descrs_t f) { + m_mk.push_back(f); } }; @@ -204,7 +202,7 @@ public: m_param_descrs.copy(d); } - void register_module(char const * module_name, lazy_descrs_t& f) { + void register_module(char const * module_name, lazy_descrs_t f) { // Don't need synchronization here, this method // is invoked from check_registered that is already protected. @@ -599,7 +597,7 @@ void gparams::register_global(param_descrs & d) { g_imp->register_global(d); } -void gparams::register_module(char const * module_name, lazy_descrs_t& f) { +void gparams::register_module(char const * module_name, lazy_descrs_t f) { SASSERT(g_imp); g_imp->register_module(module_name, f); } diff --git a/src/util/gparams.h b/src/util/gparams.h index 0efad4a07..0959c20fc 100644 --- a/src/util/gparams.h +++ b/src/util/gparams.h @@ -85,8 +85,8 @@ public: module. */ - typedef std::function lazy_descrs_t; - static void register_module(char const* module_name, lazy_descrs_t& get_descrs); + typedef param_descrs* (*lazy_descrs_t)(void); + static void register_module(char const* module_name, lazy_descrs_t get_descrs); /** \brief Add a (small) description to the given module. diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index a36e762aa..e8a72e245 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -76,56 +76,45 @@ static void thread_func(scoped_timer_state *s) { } -struct scoped_timer::imp { -private: - scoped_timer_state *s; +scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { + if (ms == 0 || ms == UINT_MAX) + return; -public: - imp(unsigned ms, event_handler * eh) { - workers.lock(); - bool new_worker = false; - if (available_workers.empty()) { - workers.unlock(); - s = new scoped_timer_state; - new_worker = true; - ++num_workers; - } - else { - s = available_workers.back(); - available_workers.pop_back(); - workers.unlock(); - } - s->ms = ms; - s->eh = eh; - s->m_mutex.lock(); - s->work = WORKING; - if (new_worker) { - s->m_thread = std::thread(thread_func, s); - } - else { - s->cv.notify_one(); - } + workers.lock(); + bool new_worker = false; + if (available_workers.empty()) { + workers.unlock(); + s = new scoped_timer_state; + new_worker = true; + ++num_workers; } - - ~imp() { - s->m_mutex.unlock(); - while (s->work == WORKING) - std::this_thread::yield(); - workers.lock(); - available_workers.push_back(s); + else { + s = available_workers.back(); + available_workers.pop_back(); workers.unlock(); } -}; - -scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { - if (ms != UINT_MAX && ms != 0) - m_imp = alloc(imp, ms, eh); - else - m_imp = nullptr; + s->ms = ms; + s->eh = eh; + s->m_mutex.lock(); + s->work = WORKING; + if (new_worker) { + s->m_thread = std::thread(thread_func, s); + } + else { + s->cv.notify_one(); + } } scoped_timer::~scoped_timer() { - dealloc(m_imp); + if (!s) + return; + + s->m_mutex.unlock(); + while (s->work == WORKING) + std::this_thread::yield(); + workers.lock(); + available_workers.push_back(s); + workers.unlock(); } void scoped_timer::initialize() { diff --git a/src/util/scoped_timer.h b/src/util/scoped_timer.h index 95920b71f..dfd97810c 100644 --- a/src/util/scoped_timer.h +++ b/src/util/scoped_timer.h @@ -20,9 +20,10 @@ Revision History: #include "util/event_handler.h" +struct scoped_timer_state; + class scoped_timer { - struct imp; - imp * m_imp; + scoped_timer_state *s = nullptr; public: scoped_timer(unsigned ms, event_handler * eh); ~scoped_timer(); From 412b05076ce3ebc28a1ef567c7d5841f51ad934a Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Sat, 26 Feb 2022 18:21:01 +0100 Subject: [PATCH 076/258] User-functions fix (#5868) --- src/api/c++/z3++.h | 110 ++++++++++++++++++----------- src/smt/smt_context.cpp | 11 +-- src/smt/smt_context.h | 2 +- src/smt/theory_user_propagator.cpp | 36 ++++++++-- src/smt/theory_user_propagator.h | 2 +- 5 files changed, 107 insertions(+), 54 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 0bbab4185..970a96c72 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -25,6 +25,7 @@ Notes: #include #include #include +#include #include #include #include @@ -542,7 +543,7 @@ namespace z3 { ~ast_vector_tpl() { Z3_ast_vector_dec_ref(ctx(), m_vector); } operator Z3_ast_vector() const { return m_vector; } unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); } - T operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast()(ctx(), r); } + T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast()(ctx(), r); } void push_back(T const & e) { Z3_ast_vector_push(ctx(), m_vector, e); check_error(); } void resize(unsigned sz) { Z3_ast_vector_resize(ctx(), m_vector, sz); check_error(); } T back() const { return operator[](size() - 1); } @@ -1149,6 +1150,19 @@ namespace z3 { \pre i < num_args() */ expr arg(unsigned i) const { Z3_ast r = Z3_get_app_arg(ctx(), *this, i); check_error(); return expr(ctx(), r); } + /** + \brief Return a vector of all the arguments of this application. + This method assumes the expression is an application. + + \pre is_app() + */ + expr_vector args() const { + expr_vector vec(ctx()); + unsigned argCnt = num_args(); + for (unsigned i = 0; i < argCnt; i++) + vec.push_back(arg(i)); + return vec; + } /** \brief Return the 'body' of this quantifier. @@ -3936,7 +3950,8 @@ namespace z3 { created_eh_t m_created_eh; solver* s; context* c; - + std::vector subcontexts; + Z3_solver_callback cb { nullptr }; struct scoped_cb { @@ -3944,8 +3959,8 @@ namespace z3 { scoped_cb(void* _p, Z3_solver_callback cb):p(*static_cast(_p)) { p.cb = cb; } - ~scoped_cb() { - p.cb = nullptr; + ~scoped_cb() { + p.cb = nullptr; } }; @@ -3958,7 +3973,9 @@ namespace z3 { } static void* fresh_eh(void* p, Z3_context ctx) { - return static_cast(p)->fresh(ctx); + context* c = new context(ctx); + static_cast(p)->subcontexts.push_back(c); + return static_cast(p)->fresh(*c); } static void fixed_eh(void* _p, Z3_solver_callback cb, Z3_ast _var, Z3_ast _value) { @@ -3993,60 +4010,69 @@ namespace z3 { user_propagator_base(context& c) : s(nullptr), c(&c) {} user_propagator_base(solver* s): s(s), c(nullptr) { - Z3_solver_propagate_init(ctx(), *s, this, push_eh, pop_eh, fresh_eh); + Z3_solver_propagate_init(ctx(), *s, this, push_eh, pop_eh, fresh_eh); } virtual void push() = 0; virtual void pop(unsigned num_scopes) = 0; - virtual ~user_propagator_base() = default; + virtual ~user_propagator_base() { + for (auto& subcontext : subcontexts) { + subcontext->detach(); // detach first; the subcontexts will be freed internally! + delete subcontext; + } + } context& ctx() { - return c ? *c : s->ctx(); + return c ? *c : s->ctx(); } /** - \brief user_propagators created using \c fresh() are created during + \brief user_propagators created using \c fresh() are created during search and their lifetimes are restricted to search time. They should be garbage collected by the propagator used to invoke \c fresh(). The life-time of the Z3_context object can only be assumed valid during callbacks, such as \c fixed(), which contains expressions based on the context. */ - virtual user_propagator_base* fresh(Z3_context ctx) = 0; + virtual user_propagator_base* fresh(context& ctx) = 0; /** \brief register callbacks. Callbacks can only be registered with user_propagators - that were created using a solver. + that were created using a solver. */ - void register_fixed(fixed_eh_t& f) { - assert(s); - m_fixed_eh = f; - Z3_solver_propagate_fixed(ctx(), *s, fixed_eh); + void register_fixed(fixed_eh_t& f) { + m_fixed_eh = f; + if (s) { + Z3_solver_propagate_fixed(ctx(), *s, fixed_eh); + } } void register_fixed() { - assert(s); - m_fixed_eh = [this](expr const& id, expr const& e) { + m_fixed_eh = [this](expr const &id, expr const &e) { fixed(id, e); }; - Z3_solver_propagate_fixed(ctx(), *s, fixed_eh); + if (s) { + Z3_solver_propagate_fixed(ctx(), *s, fixed_eh); + } } - void register_eq(eq_eh_t& f) { - assert(s); - m_eq_eh = f; - Z3_solver_propagate_eq(ctx(), *s, eq_eh); + void register_eq(eq_eh_t& f) { + m_eq_eh = f; + if (s) { + Z3_solver_propagate_eq(ctx(), *s, eq_eh); + } } void register_eq() { - assert(s); m_eq_eh = [this](expr const& x, expr const& y) { eq(x, y); }; - Z3_solver_propagate_eq(ctx(), *s, eq_eh); + if (s) { + Z3_solver_propagate_eq(ctx(), *s, eq_eh); + } } /** @@ -4054,34 +4080,39 @@ namespace z3 { During the final check stage, all propagations have been processed. This is an opportunity for the user-propagator to delay some analysis that could be expensive to perform incrementally. It is also an opportunity - for the propagator to implement branch and bound optimization. + for the propagator to implement branch and bound optimization. */ - void register_final(final_eh_t& f) { - assert(s); - m_final_eh = f; - Z3_solver_propagate_final(ctx(), *s, final_eh); + void register_final(final_eh_t& f) { + m_final_eh = f; + if (s) { + Z3_solver_propagate_final(ctx(), *s, final_eh); + } } - - void register_final() { - assert(s); + + void register_final() { m_final_eh = [this]() { final(); }; - Z3_solver_propagate_final(ctx(), *s, final_eh); + if (s) { + Z3_solver_propagate_final(ctx(), *s, final_eh); + } } void register_created(created_eh_t& c) { - assert(s); m_created_eh = c; - Z3_solver_propagate_created(ctx(), *s, created_eh); + if (s) { + Z3_solver_propagate_created(ctx(), *s, created_eh); + } } void register_created() { m_created_eh = [this](expr const& e) { created(e); }; - Z3_solver_propagate_created(ctx(), *s, created_eh); + if (s) { + Z3_solver_propagate_created(ctx(), *s, created_eh); + } } virtual void fixed(expr const& /*id*/, expr const& /*e*/) { } @@ -4095,10 +4126,10 @@ namespace z3 { /** \brief tracks \c e by a unique identifier that is returned by the call. - If the \c fixed() callback is registered and if \c e is a Boolean or Bit-vector, + If the \c fixed() callback is registered and if \c e is a Boolean or Bit-vector, the \c fixed() callback gets invoked when \c e is bound to a value. If the \c eq() callback is registered, then equalities between registered expressions - are reported. + are reported. A consumer can use the \c propagate or \c conflict functions to invoke propagations or conflicts as a consequence of these callbacks. These functions take a list of identifiers for registered expressions that have been fixed. The list of identifiers must correspond to @@ -4143,9 +4174,6 @@ namespace z3 { } }; - - - } /**@}*/ diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 186d03dc3..2eba2c2a2 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -171,7 +171,7 @@ namespace smt { dst_ctx.setup_context(dst_ctx.m_fparams.m_auto_config); dst_ctx.internalize_assertions(); - dst_ctx.copy_user_propagator(src_ctx); + dst_ctx.copy_user_propagator(src_ctx, true); TRACE("smt_context", src_ctx.display(tout); @@ -193,13 +193,16 @@ namespace smt { } } - void context::copy_user_propagator(context& src_ctx) { + void context::copy_user_propagator(context& src_ctx, bool copy_registered) { if (!src_ctx.m_user_propagator) return; - ast_translation tr(src_ctx.m, m, false); auto* p = get_theory(m.mk_family_id("user_propagator")); m_user_propagator = reinterpret_cast(p); SASSERT(m_user_propagator); + if (!copy_registered) { + return; + } + ast_translation tr(src_ctx.m, m, false); for (unsigned i = 0; i < src_ctx.m_user_propagator->get_num_vars(); ++i) { app* e = src_ctx.m_user_propagator->get_expr(i); m_user_propagator->add_expr(tr(e)); @@ -211,7 +214,7 @@ namespace smt { new_ctx->m_is_auxiliary = true; new_ctx->set_logic(l == nullptr ? m_setup.get_logic() : *l); copy_plugins(*this, *new_ctx); - new_ctx->copy_user_propagator(*this); + new_ctx->copy_user_propagator(*this, false); return new_ctx; } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 12f0cc2ad..f1b2514b1 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1576,7 +1576,7 @@ namespace smt { void log_stats(); - void copy_user_propagator(context& src); + void copy_user_propagator(context& src, bool copy_registered); public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 85a02b154..751386ef3 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -94,8 +94,14 @@ void theory_user_propagator::register_cb(expr* e) { } theory * theory_user_propagator::mk_fresh(context * new_ctx) { - auto* th = alloc(theory_user_propagator, *new_ctx); - void* ctx = m_fresh_eh(m_user_context, new_ctx->get_manager(), th->m_api_context); + auto* th = alloc(theory_user_propagator, *new_ctx); + void* ctx; + try { + ctx = m_fresh_eh(m_user_context, new_ctx->get_manager(), th->m_api_context); + } + catch (...) { + throw default_exception("Exception thrown in \"fresh\"-callback"); + } th->add(ctx, m_push_eh, m_pop_eh, m_fresh_eh); if ((bool)m_fixed_eh) th->register_fixed(m_fixed_eh); if ((bool)m_final_eh) th->register_final(m_final_eh); @@ -110,7 +116,12 @@ final_check_status theory_user_propagator::final_check_eh() { return FC_DONE; force_push(); unsigned sz = m_prop.size(); - m_final_eh(m_user_context, this); + try { + m_final_eh(m_user_context, this); + } + catch (...) { + throw default_exception("Exception thrown in \"final\"-callback"); + } propagate(); bool done = (sz == m_prop.size()) && !ctx.inconsistent(); return done ? FC_DONE : FC_CONTINUE; @@ -125,7 +136,12 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu m_fixed.insert(v); ctx.push_trail(insert_map(m_fixed, v)); m_id2justification.setx(v, literal_vector(num_lits, jlits), literal_vector()); - m_fixed_eh(m_user_context, this, var2expr(v), value); + try { + m_fixed_eh(m_user_context, this, var2expr(v), value); + } + catch (...) { + throw default_exception("Exception thrown in \"fixed\"-callback"); + } } void theory_user_propagator::push_scope_eh() { @@ -228,11 +244,17 @@ bool theory_user_propagator::internalize_term(app* term) { ctx.mk_enode(term, true, false, true); add_expr(term); + + if (!m_created_eh) + throw default_exception("You have to register a created event handler for new terms if you track them"); - if (!m_created_eh && (m_fixed_eh || m_eq_eh || m_diseq_eh)) - return true; - if (m_created_eh) + try { m_created_eh(m_user_context, this, term); + } + catch (...) { + throw default_exception("Exception thrown in \"created\"-callback"); + } + return true; } diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index e1aa33b8e..1045feb0a 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -142,7 +142,7 @@ namespace smt { void collect_statistics(::statistics & st) const override; model_value_proc * mk_value(enode * n, model_generator & mg) override { return nullptr; } void init_model(model_generator & m) override {} - bool include_func_interp(func_decl* f) override { return true; } + bool include_func_interp(func_decl* f) override { return false; } bool can_propagate() override; void propagate() override; void display(std::ostream& out) const override {} From 302c0d178c700dea0b29aa005f26a4971d90c00e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Feb 2022 09:50:07 -0800 Subject: [PATCH 077/258] fix #5867 --- src/tactic/core/pb_preprocess_tactic.cpp | 79 +++++++++++++----------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 1d40a91c7..0313899ac 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -119,42 +119,38 @@ public: } generic_model_converter* pp = alloc(generic_model_converter, m, "pb-preprocess"); - g->add(pp); g->inc_depth(); result.push_back(g.get()); while (simplify(g, *pp)); + g->add(pp); + // decompose(g); } bool simplify(goal_ref const& g, generic_model_converter& mc) { reset(); normalize(g); - if (g->inconsistent()) { + if (g->inconsistent()) return false; - } - for (unsigned i = 0; i < g->size(); ++i) { - process_vars(i, g); - } - - if (m_ge.empty()) { + + for (unsigned i = 0; i < g->size(); ++i) + process_vars(i, g); + + if (m_ge.empty()) return false; - } - for (unsigned i = 0; i < m_ge.size(); ++i) { + for (unsigned i = 0; i < m_ge.size(); ++i) if (!classify_vars(i, to_app(g->form(m_ge[i])))) return false; - } declassifier dcl(m_vars); expr_mark visited; - for (unsigned i = 0; !m_vars.empty() && i < m_other.size(); ++i) { + for (unsigned i = 0; !m_vars.empty() && i < m_other.size(); ++i) for_each_expr(dcl, visited, g->form(m_other[i])); - } - if (m_vars.empty()) { + if (m_vars.empty()) return false; - } // display_annotation(tout, g); m_progress = false; @@ -172,24 +168,23 @@ public: replace(r.pos, e, m.mk_true(), g); set_value(mc, e, true); } - if (g->inconsistent()) return false; + if (g->inconsistent()) + return false; ++it; it = next_resolvent(it); } // now resolve clauses. it = next_resolvent(m_vars.begin()); - while (it != m_vars.end()) { - + while (it != m_vars.end()) { app * e = it->m_key; SASSERT(is_uninterp_const(e)); rec const& r = it->m_value; - if (r.pos.size() == 1 && !r.neg.empty()) { + if (r.pos.size() == 1 && !r.neg.empty()) resolve(mc, r.pos[0], r.neg, e, true, g); - } - else if (r.neg.size() == 1 && !r.pos.empty()) { + else if (r.neg.size() == 1 && !r.pos.empty()) resolve(mc, r.neg[0], r.pos, e, false, g); - } - if (g->inconsistent()) return false; + if (g->inconsistent()) + return false; ++it; it = next_resolvent(it); } @@ -201,20 +196,29 @@ public: vector coeffs1, coeffs2; rational k1, k2; expr* fml = g->form(m_ge[i]); - if (!to_ge(fml, args1, coeffs1, k1)) continue; - if (args1.empty()) continue; + if (!to_ge(fml, args1, coeffs1, k1)) + continue; + if (args1.empty()) + continue; expr* arg = args1.get(0); bool neg = m.is_not(arg, arg); - if (!is_uninterp_const(arg)) continue; - if (!m_vars.contains(to_app(arg))) continue; + if (!is_uninterp_const(arg)) + continue; + if (!m_vars.contains(to_app(arg))) + continue; rec const& r = m_vars.find(to_app(arg)); unsigned_vector const& pos = neg?r.neg:r.pos; for (unsigned j = 0; j < pos.size(); ++j) { unsigned k = pos[j]; - if (k == m_ge[i]) continue; - if (!to_ge(g->form(k), args2, coeffs2, k2)) continue; + if (k == m_ge[i]) + continue; + coeffs2.reset(); + args2.reset(); + if (!to_ge(g->form(k), args2, coeffs2, k2)) + continue; if (subsumes(args1, coeffs1, k1, args2, coeffs2, k2)) { - IF_VERBOSE(3, verbose_stream() << "replace " << mk_pp(g->form(k), m) << "\n";); + IF_VERBOSE(3, verbose_stream() << "subsumes " << mk_pp(fml, m) << "\n"); + IF_VERBOSE(3, verbose_stream() << "replace " << mk_pp(g->form(k), m) << "\n"); g->update(k, m.mk_true(), nullptr, m.mk_join(g->dep(m_ge[i]), g->dep(k))); m_progress = true; } @@ -417,12 +421,10 @@ private: m_trail.push_back(e); m_vars.insert(e, rec()); } - if (pos) { + if (pos) m_vars.find(e).pos.push_back(i); - } - else { + else m_vars.find(e).neg.push_back(i); - } } bool pure_args(app* a) const { @@ -631,16 +633,19 @@ private: vector const& coeffs1, rational const& k1, expr_ref_vector const& args2, vector const& coeffs2, rational const& k2) { - if (k2 > k1) return false; + if (k2 > k1) + return false; for (unsigned i = 0; i < args1.size(); ++i) { bool found = false; for (unsigned j = 0; !found && j < args2.size(); ++j) { if (args1[i] == args2[j]) { - if (coeffs1[i] > coeffs2[j]) return false; + if (coeffs1[i] > coeffs2[j]) + return false; found = true; } } - if (!found) return false; + if (!found) + return false; } return true; } From 2b6dadcbc661400ae0334e14b0e3c1f200988cf3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Feb 2022 17:02:13 -0800 Subject: [PATCH 078/258] fix #5869 Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_rule_inliner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 7b22b4133..7a47f77f9 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -801,7 +801,7 @@ namespace datalog { if (num_tail_unifiers == 1) { TRACE("dl", tout << "setting invalid: " << j << "\n";); valid.set(j, false); - datalog::del_rule(m_mc, *r2, l_true); + datalog::del_rule(m_mc, *r2, l_false); del_rule(r2, j); } From deaad86d6a0e5e02abdf1164c7deee7855a765eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Mar 2022 11:11:20 -0800 Subject: [PATCH 079/258] nit --- src/api/c++/z3++.h | 6 ++++-- src/smt/theory_user_propagator.cpp | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 970a96c72..1a2def0c8 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2587,9 +2587,9 @@ namespace z3 { friend std::ostream & operator<<(std::ostream & out, model const & m); - std::string to_string() const { return std::string(Z3_model_to_string(ctx(), m_model)); } + std::string to_string() const { return m_model ? std::string(Z3_model_to_string(ctx(), m_model)) : "null"; } }; - inline std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; } + inline std::ostream & operator<<(std::ostream & out, model const & m) { return out << m.to_string(); } class stats : public object { Z3_stats m_stats; @@ -3983,6 +3983,7 @@ namespace z3 { scoped_cb _cb(p, cb); expr value(p->ctx(), _value); expr var(p->ctx(), _var); + std::cout << "Fixed " << cb << "\n"; p->m_fixed_eh(var, value); } @@ -4150,6 +4151,7 @@ namespace z3 { assert(cb); expr conseq = ctx().bool_val(false); array _fixed(fixed); + std::cout << "conflict " << cb << " " << fixed << "\n"; Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq); } diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 751386ef3..3f5310ce5 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -100,7 +100,7 @@ theory * theory_user_propagator::mk_fresh(context * new_ctx) { ctx = m_fresh_eh(m_user_context, new_ctx->get_manager(), th->m_api_context); } catch (...) { - throw default_exception("Exception thrown in \"fresh\"-callback"); + throw default_exception("Exception thrown in \"fresh\"-callback"); } th->add(ctx, m_push_eh, m_pop_eh, m_fresh_eh); if ((bool)m_fixed_eh) th->register_fixed(m_fixed_eh); @@ -140,7 +140,7 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu m_fixed_eh(m_user_context, this, var2expr(v), value); } catch (...) { - throw default_exception("Exception thrown in \"fixed\"-callback"); + throw default_exception("Exception thrown in \"fixed\"-callback"); } } @@ -252,7 +252,7 @@ bool theory_user_propagator::internalize_term(app* term) { m_created_eh(m_user_context, this, term); } catch (...) { - throw default_exception("Exception thrown in \"created\"-callback"); + throw default_exception("Exception thrown in \"created\"-callback"); } return true; From c0826d58bf1d61783120dd1c73160709ca902e38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Mar 2022 12:11:02 -0800 Subject: [PATCH 080/258] add stubs for native model and func interp Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/CMakeLists.txt | 2 + src/api/dotnet/NativeFuncInterp.cs | 225 ++++++++++++++++++++ src/api/dotnet/NativeModel.cs | 329 +++++++++++++++++++++++++++++ 3 files changed, 556 insertions(+) create mode 100644 src/api/dotnet/NativeFuncInterp.cs create mode 100644 src/api/dotnet/NativeModel.cs diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 5c722c828..25b3136ad 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -86,6 +86,8 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE Log.cs Model.cs NativeContext.cs + NativeFuncInterp.cs + NativeModel.cs Optimize.cs ParamDescrs.cs Params.cs diff --git a/src/api/dotnet/NativeFuncInterp.cs b/src/api/dotnet/NativeFuncInterp.cs new file mode 100644 index 000000000..718462af9 --- /dev/null +++ b/src/api/dotnet/NativeFuncInterp.cs @@ -0,0 +1,225 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + NativeFuncInterp.cs + +Abstract: + + Z3 Managed API: Function Interpretations + +Author: + + Christoph Wintersteiger (cwinter) 2012-03-21 + +Notes: + +--*/ + +using System.Diagnostics; +using System; + +namespace Microsoft.Z3 +{ + /// + /// A function interpretation is represented as a finite map and an 'else' value. + /// Each entry in the finite map represents the value of a function given a set of arguments. + /// + public class NativeFuncInterp : IDisposable + { + +#if false + /// + /// An Entry object represents an element in the finite map used to encode + /// a function interpretation. + /// + public class Entry : Z3Object + { + /// + /// Return the (symbolic) value of this entry. + /// + public Expr Value + { + get + { + return Expr.Create(Context, Native.Z3_func_entry_get_value(Context.nCtx, NativeObject)); + } + } + + /// + /// The number of arguments of the entry. + /// + public uint NumArgs + { + get { return Native.Z3_func_entry_get_num_args(Context.nCtx, NativeObject); } + } + + /// + /// The arguments of the function entry. + /// + public Expr[] Args + { + get + { + + uint n = NumArgs; + Expr[] res = new Expr[n]; + for (uint i = 0; i < n; i++) + res[i] = Expr.Create(Context, Native.Z3_func_entry_get_arg(Context.nCtx, NativeObject, i)); + return res; + } + } + + /// + /// A string representation of the function entry. + /// + public override string ToString() + { + uint n = NumArgs; + string res = "["; + Expr[] args = Args; + for (uint i = 0; i < n; i++) + res += args[i] + ", "; + return res + Value + "]"; + } + + #region Internal + internal Entry(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } + + internal class DecRefQueue : IDecRefQueue + { + public DecRefQueue() : base() { } + public DecRefQueue(uint move_limit) : base(move_limit) { } + internal override void IncRef(Context ctx, IntPtr obj) + { + Native.Z3_func_entry_inc_ref(ctx.nCtx, obj); + } + + internal override void DecRef(Context ctx, IntPtr obj) + { + Native.Z3_func_entry_dec_ref(ctx.nCtx, obj); + } + }; + + internal override void IncRef(IntPtr o) + { + Context.FuncEntry_DRQ.IncAndClear(Context, o); + base.IncRef(o); + } + + internal override void DecRef(IntPtr o) + { + Context.FuncEntry_DRQ.Add(o); + base.DecRef(o); + } + #endregion + }; + + /// + /// The number of entries in the function interpretation. + /// + public uint NumEntries + { + get { return Native.Z3_func_interp_get_num_entries(Context.nCtx, NativeObject); } + } + + /// + /// The entries in the function interpretation + /// + public Entry[] Entries + { + get + { + + uint n = NumEntries; + Entry[] res = new Entry[n]; + for (uint i = 0; i < n; i++) + res[i] = new Entry(Context, Native.Z3_func_interp_get_entry(Context.nCtx, NativeObject, i)); + return res; + } + } + + /// + /// The (symbolic) `else' value of the function interpretation. + /// + public Expr Else + { + get + { + + return Expr.Create(Context, Native.Z3_func_interp_get_else(Context.nCtx, NativeObject)); + } + } + + /// + /// The arity of the function interpretation + /// + public uint Arity + { + get { return Native.Z3_func_interp_get_arity(Context.nCtx, NativeObject); } + } + + /// + /// A string representation of the function interpretation. + /// + public override string ToString() + { + string res = ""; + res += "["; + foreach (Entry e in Entries) + { + uint n = e.NumArgs; + if (n > 1) res += "["; + Expr[] args = e.Args; + for (uint i = 0; i < n; i++) + { + if (i != 0) res += ", "; + res += args[i]; + } + if (n > 1) res += "]"; + res += " -> " + e.Value + ", "; + } + res += "else -> " + Else; + res += "]"; + return res; + } + +#endif + + #region Internal + NativeContext Context; + IntPtr NativeObject; + internal NativeFuncInterp(NativeContext ctx, IntPtr obj) + { + Context = ctx; + NativeObject = obj; + Debug.Assert(ctx != null); + // inc-ref + } + + /// + /// Finalizer. + /// + ~NativeFuncInterp() + { + Dispose(); + } + + /// + /// Disposes of the underlying native Z3 object. + /// + public void Dispose() + { + if (NativeObject != IntPtr.Zero) + { + Native.Z3_func_interp_dec_ref(Context.nCtx, NativeObject); + NativeObject = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + + + #endregion + } +} diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs new file mode 100644 index 000000000..8a31af32f --- /dev/null +++ b/src/api/dotnet/NativeModel.cs @@ -0,0 +1,329 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + NativeModel.cs + +Abstract: + + Z3 Managed API: Models + Native interface to model objects. + +Author: + + Christoph Wintersteiger (cwinter) 2012-03-21 + Nikolaj Bjorner (nbjorner) 2022-03-01 + +Notes: + +--*/ + +using System; +using System.Diagnostics; +using System.Collections.Generic; + +namespace Microsoft.Z3 +{ + using Z3_context = System.IntPtr; + using Z3_ast = System.IntPtr; + using Z3_app = System.IntPtr; + using Z3_sort = System.IntPtr; + using Z3_func_decl = System.IntPtr; + using Z3_model = System.IntPtr; + using Z3_func_interp = System.IntPtr; + using Z3_func_entry = System.IntPtr; + + /// + /// A Model contains interpretations (assignments) of constants and functions. + /// + public class NativeModel + { + /// + /// Retrieves the interpretation (the assignment) of in the model. + /// + /// A Constant + /// An expression if the constant has an interpretation in the model, null otherwise. + public Z3_ast ConstInterp(Z3_ast a) => ConstInterp(Native.Z3_get_app_decl(Context.nCtx, a)); + + /// + /// Retrieves the interpretation (the assignment) of in the model. + /// + /// A function declaration of zero arity + /// An expression if the function has an interpretation in the model, null otherwise. + public Z3_ast ConstFuncInterp(Z3_func_decl f) + { + if (Native.Z3_get_arity(Context.nCtx, f) != 0) + throw new Z3Exception("Non-zero arity functions have FunctionInterpretations as a model. Use FuncInterp."); + + return Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); + } + + /// + /// Retrieves the interpretation (the assignment) of a non-constant in the model. + /// + /// A function declaration of non-zero arity + /// A FunctionInterpretation if the function has an interpretation in the model, null otherwise. + public NativeFuncInterp FuncInterp(Z3_func_decl f) + { + + Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_range(Context.nCtx, f)); + + if (Native.Z3_get_arity(Context.nCtx, f) == 0) + { + IntPtr n = Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); + + if (sk == Z3_sort_kind.Z3_ARRAY_SORT) + { + if (n == IntPtr.Zero) + return null; + else + { + if (Native.Z3_is_as_array(Context.nCtx, n) == 0) + throw new Z3Exception("Argument was not an array constant"); + var fd = Native.Z3_get_as_array_func_decl(Context.nCtx, n); + return new NativeFuncInterp(Context, fd); + } + } + else + { + throw new Z3Exception("Constant functions do not have a function interpretation; use ConstInterp"); + } + } + else + { + IntPtr n = Native.Z3_model_get_func_interp(Context.nCtx, NativeObject, f); + if (n == IntPtr.Zero) + return null; + else + return new NativeFuncInterp(Context, n); + } + } + + + + /// + /// The number of constants that have an interpretation in the model. + /// + public uint NumConsts + { + get { return Native.Z3_model_get_num_consts(Context.nCtx, NativeObject); } + } + + + /// + /// The function declarations of the constants in the model. + /// + public Z3_func_decl[] ConstDecls + { + get + { + + uint n = NumConsts; + Z3_func_decl[] res = new Z3_func_decl[n]; + for (uint i = 0; i < n; i++) + res[i] = Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i); + return res; + } + } + + + /// + /// Enumerate constants in model. + /// + public IEnumerable> Consts + { + get + { + uint nc = NumConsts; + for (uint i = 0; i < nc; ++i) + { + var f = Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i); + IntPtr n = Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); + if (n == IntPtr.Zero) continue; + yield return new KeyValuePair(f, n); + } + } + } + + + /// + /// The number of function interpretations in the model. + /// + public uint NumFuncs + { + get { return Native.Z3_model_get_num_funcs(Context.nCtx, NativeObject); } + } + +#if false + + /// + /// The function declarations of the function interpretations in the model. + /// + public FuncDecl[] FuncDecls + { + get + { + + uint n = NumFuncs; + FuncDecl[] res = new FuncDecl[n]; + for (uint i = 0; i < n; i++) + res[i] = new FuncDecl(Context, Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i)); + return res; + } + } + + /// + /// All symbols that have an interpretation in the model. + /// + public FuncDecl[] Decls + { + get + { + + uint nFuncs = NumFuncs; + uint nConsts = NumConsts; + uint n = nFuncs + nConsts; + FuncDecl[] res = new FuncDecl[n]; + for (uint i = 0; i < nConsts; i++) + res[i] = new FuncDecl(Context, Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i)); + for (uint i = 0; i < nFuncs; i++) + res[nConsts + i] = new FuncDecl(Context, Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i)); + return res; + } + } + + /// + /// A ModelEvaluationFailedException is thrown when an expression cannot be evaluated by the model. + /// + public class ModelEvaluationFailedException : Z3Exception + { + /// + /// An exception that is thrown when model evaluation fails. + /// + public ModelEvaluationFailedException() : base() { } + } + + /// + /// Evaluates the expression in the current model. + /// + /// + /// This function may fail if contains quantifiers, + /// is partial (MODEL_PARTIAL enabled), or if is not well-sorted. + /// In this case a ModelEvaluationFailedException is thrown. + /// + /// An expression + /// + /// When this flag is enabled, a model value will be assigned to any constant + /// or function that does not have an interpretation in the model. + /// + /// The evaluation of in the model. + public Z3_ast Eval(Z3_ast t, bool completion = false) + { + Debug.Assert(t != null); + + IntPtr v = IntPtr.Zero; + if (Native.Z3_model_eval(Context.nCtx, NativeObject, t.NativeObject, (byte)(completion ? 1 : 0), ref v) == (byte)0) + throw new ModelEvaluationFailedException(); + else + return Z3_ast.Create(Context, v); + } + + /// + /// Alias for Eval. + /// + public Z3_ast Evaluate(Z3_ast t, bool completion = false) + { + Debug.Assert(t != null); + + return Eval(t, completion); + } + + /// + /// Evaluate expression to a double, assuming it is a numeral already. + /// + public double Double(Z3_ast t) { + var r = Eval(t, true); + return Native.Z3_get_numeral_double(Context.nCtx, r); + } + + /// + /// The number of uninterpreted sorts that the model has an interpretation for. + /// + public uint NumSorts { get { return Native.Z3_model_get_num_sorts(Context.nCtx, NativeObject); } } + + /// + /// The uninterpreted sorts that the model has an interpretation for. + /// + /// + /// Z3 also provides an interpretation for uninterpreted sorts used in a formula. + /// The interpretation for a sort is a finite set of distinct values. We say this finite set is + /// the "universe" of the sort. + /// + /// + /// + public Sort[] Sorts + { + get + { + + uint n = NumSorts; + Sort[] res = new Sort[n]; + for (uint i = 0; i < n; i++) + res[i] = Sort.Create(Context, Native.Z3_model_get_sort(Context.nCtx, NativeObject, i)); + return res; + } + } + +#endif + + /// + /// Conversion of models to strings. + /// + /// A string representation of the model. + public override string ToString() + { + return Native.Z3_model_to_string(Context.nCtx, NativeObject); + } + + + + IntPtr NativeObject; + NativeContext Context; + + internal NativeModel(NativeContext ctx, IntPtr obj) + { + Context = ctx; + NativeObject = obj; + Debug.Assert(ctx != null); + Native.Z3_model_inc_ref(ctx.nCtx, obj); + } + + + /// + /// Finalizer. + /// + ~NativeModel() + { + Dispose(); + } + + /// + /// Disposes of the underlying native Z3 object. + /// + public void Dispose() + { + if (NativeObject != IntPtr.Zero) + { + Native.Z3_model_dec_ref(Context.nCtx, NativeObject); + NativeObject = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + + + } +} + + + From deeb5e9921bf3eefb3413be29be778279f147f0e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Mar 2022 12:40:03 -0800 Subject: [PATCH 081/258] finish NativeModel Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeModel.cs | 39 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index 8a31af32f..234f3759d 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -37,7 +37,7 @@ namespace Microsoft.Z3 /// /// A Model contains interpretations (assignments) of constants and functions. /// - public class NativeModel + public class NativeModel : IDisposable { /// /// Retrieves the interpretation (the assignment) of in the model. @@ -155,28 +155,28 @@ namespace Microsoft.Z3 get { return Native.Z3_model_get_num_funcs(Context.nCtx, NativeObject); } } -#if false /// /// The function declarations of the function interpretations in the model. /// - public FuncDecl[] FuncDecls + public Z3_func_decl[] FuncDecls { get { uint n = NumFuncs; - FuncDecl[] res = new FuncDecl[n]; + Z3_func_decl[] res = new Z3_func_decl[n]; for (uint i = 0; i < n; i++) - res[i] = new FuncDecl(Context, Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i)); + res[i] = Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i); return res; } } + /// /// All symbols that have an interpretation in the model. /// - public FuncDecl[] Decls + public Z3_func_decl[] Decls { get { @@ -184,11 +184,11 @@ namespace Microsoft.Z3 uint nFuncs = NumFuncs; uint nConsts = NumConsts; uint n = nFuncs + nConsts; - FuncDecl[] res = new FuncDecl[n]; + Z3_func_decl[] res = new Z3_func_decl[n]; for (uint i = 0; i < nConsts; i++) - res[i] = new FuncDecl(Context, Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i)); + res[i] = Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i); for (uint i = 0; i < nFuncs; i++) - res[nConsts + i] = new FuncDecl(Context, Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i)); + res[nConsts + i] = Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i); return res; } } @@ -204,6 +204,7 @@ namespace Microsoft.Z3 public ModelEvaluationFailedException() : base() { } } + /// /// Evaluates the expression in the current model. /// @@ -220,24 +221,19 @@ namespace Microsoft.Z3 /// The evaluation of in the model. public Z3_ast Eval(Z3_ast t, bool completion = false) { - Debug.Assert(t != null); IntPtr v = IntPtr.Zero; - if (Native.Z3_model_eval(Context.nCtx, NativeObject, t.NativeObject, (byte)(completion ? 1 : 0), ref v) == (byte)0) + if (Native.Z3_model_eval(Context.nCtx, NativeObject, t, (byte)(completion ? 1 : 0), ref v) == (byte)0) throw new ModelEvaluationFailedException(); else - return Z3_ast.Create(Context, v); + return v; } /// /// Alias for Eval. /// - public Z3_ast Evaluate(Z3_ast t, bool completion = false) - { - Debug.Assert(t != null); + public Z3_ast Evaluate(Z3_ast t, bool completion = false) => Eval(t, completion); - return Eval(t, completion); - } /// /// Evaluate expression to a double, assuming it is a numeral already. @@ -252,6 +248,7 @@ namespace Microsoft.Z3 /// public uint NumSorts { get { return Native.Z3_model_get_num_sorts(Context.nCtx, NativeObject); } } + /// /// The uninterpreted sorts that the model has an interpretation for. /// @@ -262,20 +259,19 @@ namespace Microsoft.Z3 /// /// /// - public Sort[] Sorts + public Z3_sort[] Sorts { get { uint n = NumSorts; - Sort[] res = new Sort[n]; + Z3_sort[] res = new Z3_sort[n]; for (uint i = 0; i < n; i++) - res[i] = Sort.Create(Context, Native.Z3_model_get_sort(Context.nCtx, NativeObject, i)); + res[i] = Native.Z3_model_get_sort(Context.nCtx, NativeObject, i); return res; } } -#endif /// /// Conversion of models to strings. @@ -287,7 +283,6 @@ namespace Microsoft.Z3 } - IntPtr NativeObject; NativeContext Context; From 61d265477013d6671bad5c75776181f56f9f9fe1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Mar 2022 13:18:18 -0800 Subject: [PATCH 082/258] quantifier Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 62 ++++++++++++++++++++++++++++++ src/api/dotnet/NativeFuncInterp.cs | 3 +- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 57f3f96de..00ac55c67 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -6,6 +6,7 @@ using System.Linq; namespace Microsoft.Z3 { + using Z3_symbol = System.IntPtr; using Z3_config = System.IntPtr; using Z3_context = System.IntPtr; using Z3_ast = System.IntPtr; @@ -56,6 +57,67 @@ namespace Microsoft.Z3 #endregion + #region Quantifiers + /// + /// Create a universal Quantifier. + /// + /// + /// Creates a forall formula, where is the weight, + /// is an array of patterns, is an array + /// with the sorts of the bound variables, is an array with the + /// 'names' of the bound variables, and is the body of the + /// quantifier. Quantifiers are associated with weights indicating the importance of + /// using the quantifier during instantiation. + /// Note that the bound variables are de-Bruijn indices created using . + /// Z3 applies the convention that the last element in and + /// refers to the variable with index 0, the second to last element + /// of and refers to the variable + /// with index 1, etc. + /// + /// the sorts of the bound variables. + /// names of the bound variables + /// the body of the quantifier. + /// quantifiers are associated with weights indicating the importance of using the quantifier during instantiation. By default, pass the weight 0. + /// array containing the patterns created using MkPattern. + /// array containing the anti-patterns created using MkPattern. + /// optional symbol to track quantifier. + /// optional symbol to track skolem constants. + public Z3_ast MkForall(Z3_sort[] sorts, Symbol[] names, Z3_ast body, uint weight = 1, Z3_ast[] patterns = null, Z3_ast[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) + { + return MkQuantifier(true, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); + } + + /// + /// Create a quantified expression either forall or exists + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + private Z3_ast MkQuantifier(bool is_forall, Z3_sort[] sorts, Symbol[] names, Z3_ast body, uint weight, Z3_ast[] patterns, Z3_ast[] noPatterns, Symbol quantifierID, Symbol skolemID) + { + Debug.Assert(sorts != null); + Debug.Assert(names != null); + Debug.Assert(body != null); + Debug.Assert(sorts.Length == names.Length); + Debug.Assert(sorts.All(s => s != IntPtr.Zero)); + Debug.Assert(names.All(n => n != null)); + Debug.Assert(patterns == null || patterns.All(p => p != IntPtr.Zero)); + Debug.Assert(noPatterns == null || noPatterns.All(np => np != IntPtr.Zero)); + uint numPatterns = patterns == null ? 0 : (uint)patterns.Length; + uint numNoPatterns = noPatterns == null ? 0 : (uint)noPatterns.Length; + Z3_symbol[] _names = Symbol.ArrayToNative(names); + return Native.Z3_mk_quantifier_ex(nCtx, (byte)(is_forall ? 1 : 0), weight, quantifierID.NativeObject, skolemID.NativeObject, numPatterns, patterns, numNoPatterns, noPatterns, (uint)sorts.Length, sorts, _names, body); + } + + #endregion + #region Options /// /// Selects the format used for pretty-printing expressions. diff --git a/src/api/dotnet/NativeFuncInterp.cs b/src/api/dotnet/NativeFuncInterp.cs index 718462af9..bac3add04 100644 --- a/src/api/dotnet/NativeFuncInterp.cs +++ b/src/api/dotnet/NativeFuncInterp.cs @@ -30,6 +30,7 @@ namespace Microsoft.Z3 { #if false + /// /// An Entry object represents an element in the finite map used to encode /// a function interpretation. @@ -187,7 +188,7 @@ namespace Microsoft.Z3 #endif - #region Internal + #region Internal NativeContext Context; IntPtr NativeObject; internal NativeFuncInterp(NativeContext ctx, IntPtr obj) From c812d1e89086ca9c23cad8148f76c2a5985810a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Mar 2022 14:07:20 -0800 Subject: [PATCH 083/258] update native func interp Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeFuncInterp.cs | 211 ++++++----------------------- src/api/dotnet/NativeModel.cs | 40 +++--- 2 files changed, 64 insertions(+), 187 deletions(-) diff --git a/src/api/dotnet/NativeFuncInterp.cs b/src/api/dotnet/NativeFuncInterp.cs index bac3add04..86bb27c55 100644 --- a/src/api/dotnet/NativeFuncInterp.cs +++ b/src/api/dotnet/NativeFuncInterp.cs @@ -22,202 +22,79 @@ using System; namespace Microsoft.Z3 { + + using Z3_context = System.IntPtr; + using Z3_ast = System.IntPtr; + using Z3_app = System.IntPtr; + using Z3_sort = System.IntPtr; + using Z3_func_decl = System.IntPtr; + using Z3_model = System.IntPtr; + using Z3_func_interp = System.IntPtr; + using Z3_func_entry = System.IntPtr; + /// /// A function interpretation is represented as a finite map and an 'else' value. /// Each entry in the finite map represents the value of a function given a set of arguments. /// - public class NativeFuncInterp : IDisposable + public class NativeFuncInterp { -#if false - /// - /// An Entry object represents an element in the finite map used to encode - /// a function interpretation. + /// Evaluation entry of a function /// - public class Entry : Z3Object + public class Entry { /// - /// Return the (symbolic) value of this entry. + /// Argument values that define entry /// - public Expr Value - { - get - { - return Expr.Create(Context, Native.Z3_func_entry_get_value(Context.nCtx, NativeObject)); - } - } + public Z3_ast[] Arguments; /// - /// The number of arguments of the entry. + /// Result of applying function to Arguments in the interpretation /// - public uint NumArgs - { - get { return Native.Z3_func_entry_get_num_args(Context.nCtx, NativeObject); } - } - - /// - /// The arguments of the function entry. - /// - public Expr[] Args - { - get - { - - uint n = NumArgs; - Expr[] res = new Expr[n]; - for (uint i = 0; i < n; i++) - res[i] = Expr.Create(Context, Native.Z3_func_entry_get_arg(Context.nCtx, NativeObject, i)); - return res; - } - } - - /// - /// A string representation of the function entry. - /// - public override string ToString() - { - uint n = NumArgs; - string res = "["; - Expr[] args = Args; - for (uint i = 0; i < n; i++) - res += args[i] + ", "; - return res + Value + "]"; - } - - #region Internal - internal Entry(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } - - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_func_entry_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_func_entry_dec_ref(ctx.nCtx, obj); - } - }; - - internal override void IncRef(IntPtr o) - { - Context.FuncEntry_DRQ.IncAndClear(Context, o); - base.IncRef(o); - } - - internal override void DecRef(IntPtr o) - { - Context.FuncEntry_DRQ.Add(o); - base.DecRef(o); - } - #endregion - }; + public Z3_ast Result; + } /// - /// The number of entries in the function interpretation. + /// Function that is interpreted /// - public uint NumEntries - { - get { return Native.Z3_func_interp_get_num_entries(Context.nCtx, NativeObject); } - } + public Z3_func_decl Declaration; /// - /// The entries in the function interpretation + /// Set of non-default entries defining the function graph /// - public Entry[] Entries - { - get - { - - uint n = NumEntries; - Entry[] res = new Entry[n]; - for (uint i = 0; i < n; i++) - res[i] = new Entry(Context, Native.Z3_func_interp_get_entry(Context.nCtx, NativeObject, i)); - return res; - } - } + public Entry[] Entries; /// - /// The (symbolic) `else' value of the function interpretation. + /// Default cause of the function interpretation /// - public Expr Else + public Z3_ast Else; + + #region Internal + internal NativeFuncInterp(NativeContext ctx, NativeModel mdl, Z3_func_decl decl, Z3_func_interp fi) { - get - { - - return Expr.Create(Context, Native.Z3_func_interp_get_else(Context.nCtx, NativeObject)); - } - } - - /// - /// The arity of the function interpretation - /// - public uint Arity - { - get { return Native.Z3_func_interp_get_arity(Context.nCtx, NativeObject); } - } - - /// - /// A string representation of the function interpretation. - /// - public override string ToString() - { - string res = ""; - res += "["; - foreach (Entry e in Entries) - { - uint n = e.NumArgs; - if (n > 1) res += "["; - Expr[] args = e.Args; - for (uint i = 0; i < n; i++) - { - if (i != 0) res += ", "; - res += args[i]; - } - if (n > 1) res += "]"; - res += " -> " + e.Value + ", "; - } - res += "else -> " + Else; - res += "]"; - return res; - } - -#endif - - #region Internal - NativeContext Context; - IntPtr NativeObject; - internal NativeFuncInterp(NativeContext ctx, IntPtr obj) - { - Context = ctx; - NativeObject = obj; Debug.Assert(ctx != null); - // inc-ref - } + Z3_context nCtx = ctx.nCtx; + Native.Z3_func_interp_inc_ref(nCtx, fi); - /// - /// Finalizer. - /// - ~NativeFuncInterp() - { - Dispose(); - } + Declaration = decl; + Else = Native.Z3_func_interp_get_else(nCtx, fi); + uint numEntries = Native.Z3_func_interp_get_num_entries(nCtx, fi); + uint numArgs = Native.Z3_func_interp_get_arity(nCtx, fi); + Entries = new Entry[numEntries]; - /// - /// Disposes of the underlying native Z3 object. - /// - public void Dispose() - { - if (NativeObject != IntPtr.Zero) + for (uint j = 0; j < numEntries; ++j) { - Native.Z3_func_interp_dec_ref(Context.nCtx, NativeObject); - NativeObject = IntPtr.Zero; + var entry = Native.Z3_func_interp_get_entry(nCtx, fi, j); + Native.Z3_func_entry_inc_ref(nCtx, entry); + Entries[j].Arguments = new Z3_ast[numArgs]; + for (uint i = 0; i < numArgs; ++i) + Entries[j].Arguments[i] = Native.Z3_func_entry_get_arg(nCtx, entry, i); + Entries[j].Result = Native.Z3_func_entry_get_value(nCtx, entry); + Native.Z3_func_entry_dec_ref(nCtx, entry); } - GC.SuppressFinalize(this); + + Native.Z3_func_interp_dec_ref(nCtx, fi); } diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index 234f3759d..fcb536a05 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -53,7 +53,7 @@ namespace Microsoft.Z3 /// An expression if the function has an interpretation in the model, null otherwise. public Z3_ast ConstFuncInterp(Z3_func_decl f) { - if (Native.Z3_get_arity(Context.nCtx, f) != 0) + if (Native.Z3_get_arity(Context.nCtx, f) != 0) throw new Z3Exception("Non-zero arity functions have FunctionInterpretations as a model. Use FuncInterp."); return Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); @@ -68,8 +68,8 @@ namespace Microsoft.Z3 { Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_range(Context.nCtx, f)); - - if (Native.Z3_get_arity(Context.nCtx, f) == 0) + + if (Native.Z3_get_arity(Context.nCtx, f) == 0) { IntPtr n = Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); @@ -82,7 +82,7 @@ namespace Microsoft.Z3 if (Native.Z3_is_as_array(Context.nCtx, n) == 0) throw new Z3Exception("Argument was not an array constant"); var fd = Native.Z3_get_as_array_func_decl(Context.nCtx, n); - return new NativeFuncInterp(Context, fd); + return new NativeFuncInterp(Context, this, f, fd); } } else @@ -96,7 +96,7 @@ namespace Microsoft.Z3 if (n == IntPtr.Zero) return null; else - return new NativeFuncInterp(Context, n); + return new NativeFuncInterp(Context, this, f, n); } } @@ -188,7 +188,7 @@ namespace Microsoft.Z3 for (uint i = 0; i < nConsts; i++) res[i] = Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i); for (uint i = 0; i < nFuncs; i++) - res[nConsts + i] = Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i); + res[nConsts + i] = Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i); return res; } } @@ -238,9 +238,10 @@ namespace Microsoft.Z3 /// /// Evaluate expression to a double, assuming it is a numeral already. /// - public double Double(Z3_ast t) { + public double Double(Z3_ast t) + { var r = Eval(t, true); - return Native.Z3_get_numeral_double(Context.nCtx, r); + return Native.Z3_get_numeral_double(Context.nCtx, r); } /// @@ -258,7 +259,6 @@ namespace Microsoft.Z3 /// the "universe" of the sort. /// /// - /// public Z3_sort[] Sorts { get @@ -283,15 +283,15 @@ namespace Microsoft.Z3 } - IntPtr NativeObject; - NativeContext Context; - + IntPtr NativeObject; + NativeContext Context; + internal NativeModel(NativeContext ctx, IntPtr obj) { - Context = ctx; - NativeObject = obj; + Context = ctx; + NativeObject = obj; Debug.Assert(ctx != null); - Native.Z3_model_inc_ref(ctx.nCtx, obj); + Native.Z3_model_inc_ref(ctx.nCtx, obj); } @@ -299,9 +299,9 @@ namespace Microsoft.Z3 /// Finalizer. /// ~NativeModel() - { - Dispose(); - } + { + Dispose(); + } /// /// Disposes of the underlying native Z3 object. @@ -310,8 +310,8 @@ namespace Microsoft.Z3 { if (NativeObject != IntPtr.Zero) { - Native.Z3_model_dec_ref(Context.nCtx, NativeObject); - NativeObject = IntPtr.Zero; + Native.Z3_model_dec_ref(Context.nCtx, NativeObject); + NativeObject = IntPtr.Zero; } GC.SuppressFinalize(this); } From 5f79a977fb6a0eef43835d4c098d6ac18ad67982 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Mar 2022 14:27:57 -0800 Subject: [PATCH 084/258] use conventions from Context Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 00ac55c67..a8676e05b 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Linq; -namespace Microsoft.Z3 +namespace Microsoft.Z3 { using Z3_symbol = System.IntPtr; using Z3_config = System.IntPtr; @@ -41,13 +41,14 @@ namespace Microsoft.Z3 /// expressions. /// - public class NativeContext { + public class NativeContext + { #region Arithmetic /// /// Create an expression representing t[0] + t[1] + .... /// - + public Z3_ast MkAdd(params Z3_ast[] t) { Debug.Assert(t != null); @@ -112,8 +113,24 @@ namespace Microsoft.Z3 Debug.Assert(noPatterns == null || noPatterns.All(np => np != IntPtr.Zero)); uint numPatterns = patterns == null ? 0 : (uint)patterns.Length; uint numNoPatterns = noPatterns == null ? 0 : (uint)noPatterns.Length; - Z3_symbol[] _names = Symbol.ArrayToNative(names); - return Native.Z3_mk_quantifier_ex(nCtx, (byte)(is_forall ? 1 : 0), weight, quantifierID.NativeObject, skolemID.NativeObject, numPatterns, patterns, numNoPatterns, noPatterns, (uint)sorts.Length, sorts, _names, body); + if (noPatterns == null && quantifierID == null && skolemID == null) + { + return Native.Z3_mk_quantifier(nCtx, (byte)(is_forall ? 1 : 0), weight, + numPatterns, patterns, + (uint)sorts.Length, sorts, + Symbol.ArrayToNative(names), + body); + } + else + { + return Native.Z3_mk_quantifier_ex(nCtx, (byte)(is_forall ? 1 : 0), weight, + AST.GetNativeObject(quantifierID), AST.GetNativeObject(skolemID), + numPatterns, patterns, + numNoPatterns, noPatterns, + (uint)sorts.Length, sorts, + Symbol.ArrayToNative(names), + body); + } } #endregion @@ -162,5 +179,5 @@ namespace Microsoft.Z3 #endregion -} + } } \ No newline at end of file From bbadd17d5637d38e8ccd0df7ea66a1e1c2eeec44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Mar 2022 08:45:36 -0800 Subject: [PATCH 085/258] fix #5874 --- src/muz/transforms/dl_mk_rule_inliner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 7a47f77f9..f7646b14a 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -768,7 +768,7 @@ namespace datalog { break; } - rule* r2 = acc[j].get(); + rule* r2 = acc.get(j); // check that the head of r2 only unifies with this single body position. TRACE("dl", output_predicate(m_context, r2->get_head(), tout << "unify head: "); tout << "\n";); @@ -801,7 +801,7 @@ namespace datalog { if (num_tail_unifiers == 1) { TRACE("dl", tout << "setting invalid: " << j << "\n";); valid.set(j, false); - datalog::del_rule(m_mc, *r2, l_false); + datalog::del_rule(m_mc, *r2, l_undef); del_rule(r2, j); } From bf14aeb1bde040e8a5c7fb5100b8dcb3198af67a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Mar 2022 10:06:38 -0800 Subject: [PATCH 086/258] stub out nativesolver --- src/api/dotnet/CMakeLists.txt | 1 + src/api/dotnet/NativeContext.cs | 18 ++ src/api/dotnet/NativeSolver.cs | 540 ++++++++++++++++++++++++++++++++ 3 files changed, 559 insertions(+) create mode 100644 src/api/dotnet/NativeSolver.cs diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 25b3136ad..e2055cd7a 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -88,6 +88,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE NativeContext.cs NativeFuncInterp.cs NativeModel.cs + NativeSolver.cs Optimize.cs ParamDescrs.cs Params.cs diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index a8676e05b..a13e48bf7 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -179,5 +179,23 @@ namespace Microsoft.Z3 #endregion + + /// + /// Utility to convert a vector object of ast to a .Net array + /// + /// + /// + public Z3_ast[] ToArray(Z3_ast_vector vec) + { + Native.Z3_ast_vector_inc_ref(nCtx, vec); + var sz = Native.Z3_ast_vector_size(nCtx, vec); + var result = new Z3_ast[sz]; + for (uint i = 0; i < sz; ++i) + result[i] = Native.Z3_ast_vector_get(nCtx, vec, i); + Native.Z3_ast_vector_dec_ref(nCtx, vec); + return result; + + } + } } \ No newline at end of file diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs new file mode 100644 index 000000000..0c494fa33 --- /dev/null +++ b/src/api/dotnet/NativeSolver.cs @@ -0,0 +1,540 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + NativeSolver.cs + +Abstract: + + Z3 Managed API: Native Solver + +Author: + + Christoph Wintersteiger (cwinter) 2012-03-22 + Nikolaj Bjorner (nbjorner) 2022-03-01 + +Notes: + +--*/ + +using System; +using System.Diagnostics; +using System.Linq; +using System.Collections.Generic; + +namespace Microsoft.Z3 +{ + + using Z3_context = System.IntPtr; + using Z3_ast = System.IntPtr; + using Z3_app = System.IntPtr; + using Z3_sort = System.IntPtr; + using Z3_func_decl = System.IntPtr; + using Z3_model = System.IntPtr; + using Z3_func_interp = System.IntPtr; + using Z3_func_entry = System.IntPtr; + using Z3_ast_vector = System.IntPtr; + using Z3_solver = System.IntPtr; + + /// + /// Solvers. + /// + public class NativeSolver : IDisposable + { + /// + /// A string that describes all available solver parameters. + /// + public string Help + { + get + { + + return Native.Z3_solver_get_help(Context.nCtx, NativeObject); + } + } + + /// + /// Sets the solver parameters. + /// + public Params Parameters + { + set + { + Debug.Assert(value != null); + + Native.Z3_solver_set_params(Context.nCtx, NativeObject, value.NativeObject); + } + } + +#if false + /// + /// Sets parameter on the solver + /// + public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + + /// + /// Retrieves parameter descriptions for solver. + /// + public ParamDescrs ParameterDescriptions + { + get { return new ParamDescrs(Context, Native.Z3_solver_get_param_descrs(Context.nCtx, NativeObject)); } + } + +#endif + + /// + /// The current number of backtracking points (scopes). + /// + /// + /// + public uint NumScopes + { + get { return Native.Z3_solver_get_num_scopes(Context.nCtx, NativeObject); } + } + + /// + /// Creates a backtracking point. + /// + /// + public void Push() + { + Native.Z3_solver_push(Context.nCtx, NativeObject); + } + + /// + /// Backtracks backtracking points. + /// + /// Note that an exception is thrown if is not smaller than NumScopes + /// + public void Pop(uint n = 1) + { + Native.Z3_solver_pop(Context.nCtx, NativeObject, n); + } + + /// + /// Resets the Solver. + /// + /// This removes all assertions from the solver. + public void Reset() + { + Native.Z3_solver_reset(Context.nCtx, NativeObject); + } + + /// + /// Assert a constraint (or multiple) into the solver. + /// + public void Assert(params Z3_ast[] constraints) + { + Debug.Assert(constraints != null); + Debug.Assert(constraints.All(c => c != IntPtr.Zero)); + + foreach (Z3_ast a in constraints) + { + Native.Z3_solver_assert(Context.nCtx, NativeObject, a); + } + } + + /// + /// Alias for Assert. + /// + public void Add(params Z3_ast[] constraints) + { + Assert(constraints); + } + + /// + /// Alias for Assert. + /// + public void Add(IEnumerable constraints) + { + Assert(constraints.ToArray()); + } + + /// + /// Assert multiple constraints into the solver, and track them (in the unsat) core + /// using the Boolean constants in ps. + /// + /// + /// This API is an alternative to with assumptions for extracting unsat cores. + /// Both APIs can be used in the same solver. The unsat core will contain a combination + /// of the Boolean variables provided using + /// and the Boolean literals + /// provided using with assumptions. + /// + public void AssertAndTrack(Z3_ast[] constraints, Z3_ast[] ps) + { + Debug.Assert(constraints != null); + Debug.Assert(constraints.All(c => c != IntPtr.Zero)); + Debug.Assert(ps.All(c => c != IntPtr.Zero)); + if (constraints.Length != ps.Length) + throw new Z3Exception("Argument size mismatch"); + + for (int i = 0; i < constraints.Length; i++) + Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraints[i], ps[i]); + } + + /// + /// Assert a constraint into the solver, and track it (in the unsat) core + /// using the Boolean constant p. + /// + /// + /// This API is an alternative to with assumptions for extracting unsat cores. + /// Both APIs can be used in the same solver. The unsat core will contain a combination + /// of the Boolean variables provided using + /// and the Boolean literals + /// provided using with assumptions. + /// + public void AssertAndTrack(Z3_ast constraint, Z3_ast p) + { + Debug.Assert(constraint != null); + Debug.Assert(p != null); + + Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraint, p); + } + + /// + /// Load solver assertions from a file. + /// + public void FromFile(string file) + { + Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); + } + + /// + /// Load solver assertions from a string. + /// + public void FromString(string str) + { + Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); + } + + /// + /// The number of assertions in the solver. + /// + public uint NumAssertions + { + get + { + var assertions = Native.Z3_solver_get_assertions(Context.nCtx, NativeObject); + Native.Z3_ast_vector_inc_ref(Context.nCtx, assertions); + var sz = Native.Z3_ast_vector_size(Context.nCtx, assertions); + Native.Z3_ast_vector_dec_ref(Context.nCtx, assertions); + return sz; + } + } + + /// + /// The set of asserted formulas. + /// + public Z3_ast[] Assertions + { + get + { + var assertions = Native.Z3_solver_get_assertions(Context.nCtx, NativeObject); + return Context.ToArray(assertions); + } + } + + /// + /// Currently inferred units. + /// + public Z3_ast[] Units + { + get + { + var units = Native.Z3_solver_get_units(Context.nCtx, NativeObject); + return Context.ToArray(units); + } + } + + /// + /// Checks whether the assertions in the solver are consistent or not. + /// + /// + /// + /// + /// + /// + public Status Check(params Z3_ast[] assumptions) + { + Z3_lbool r; + if (assumptions == null || assumptions.Length == 0) + r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); + else + r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)assumptions.Length, assumptions); + return lboolToStatus(r); + } + + /// + /// Checks whether the assertions in the solver are consistent or not. + /// + /// + /// + /// + /// + /// + public Status Check(IEnumerable assumptions) + { + Z3_lbool r; + Z3_ast[] asms = assumptions.ToArray(); + if (asms.Length == 0) + r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); + else + r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)asms.Length, asms); + return lboolToStatus(r); + } + +#if false + /// + /// Retrieve fixed assignments to the set of variables in the form of consequences. + /// Each consequence is an implication of the form + /// + /// relevant-assumptions Implies variable = value + /// + /// where the relevant assumptions is a subset of the assumptions that are passed in + /// and the equality on the right side of the implication indicates how a variable + /// is fixed. + /// + /// + /// + /// + /// + /// + public Status Consequences(IEnumerable assumptions, IEnumerable variables, out Z3_ast[] consequences) + { + ASTVector result = new ASTVector(Context); + ASTVector asms = new ASTVector(Context); + ASTVector vars = new ASTVector(Context); + foreach (var asm in assumptions) asms.Push(asm); + foreach (var v in variables) vars.Push(v); + Z3_lbool r = (Z3_lbool)Native.Z3_solver_get_consequences(Context.nCtx, NativeObject, asms.NativeObject, vars.NativeObject, result.NativeObject); + consequences = result.ToBoolExprArray(); + return lboolToStatus(r); + } +#endif + + /// + /// The model of the last Check(params Expr[] assumptions). + /// + /// + /// The result is null if Check(params Expr[] assumptions) was not invoked before, + /// if its results was not SATISFIABLE, or if model production is not enabled. + /// + public NativeModel Model + { + get + { + IntPtr x = Native.Z3_solver_get_model(Context.nCtx, NativeObject); + if (x == IntPtr.Zero) + return null; + else + return new NativeModel(Context, x); + } + } + + /// + /// The proof of the last Check(params Expr[] assumptions). + /// + /// + /// The result is null if Check(params Expr[] assumptions) was not invoked before, + /// if its results was not UNSATISFIABLE, or if proof production is disabled. + /// + public Z3_ast Proof + { + get + { + return Native.Z3_solver_get_proof(Context.nCtx, NativeObject); + } + } + + /// + /// The unsat core of the last Check. + /// + /// + /// The unsat core is a subset of Assertions + /// The result is empty if Check was not invoked before, + /// if its results was not UNSATISFIABLE, or if core production is disabled. + /// + public Z3_ast[] UnsatCore + { + get + { + return Context.ToArray(Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); + } + } + + /// + /// A brief justification of why the last call to Check returned UNKNOWN. + /// + public string ReasonUnknown + { + get + { + return Native.Z3_solver_get_reason_unknown(Context.nCtx, NativeObject); + } + } + + /// + /// Backtrack level that can be adjusted by conquer process + /// + public uint BacktrackLevel { get; set; } + +#if false + /// + /// Variables available and returned by the cuber. + /// + public Z3_ast[] CubeVariables { get; set; } + + + /// + /// Return a set of cubes. + /// + public IEnumerable Cube() + { + ASTVector cv = new ASTVector(Context); + if (CubeVariables != null) + foreach (var b in CubeVariables) cv.Push(b); + + while (true) + { + var lvl = BacktrackLevel; + BacktrackLevel = uint.MaxValue; + ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl)); + var v = r.ToBoolExprArray(); + CubeVariables = cv.ToBoolExprArray(); + if (v.Length == 1 && v[0].IsFalse) + { + break; + } + yield return v; + if (v.Length == 0) + { + break; + } + } + } +#endif + /// + /// Create a clone of the current solver with respect to ctx. + /// + public NativeSolver Translate(NativeContext ctx) + { + Debug.Assert(ctx != null); + return new NativeSolver(ctx, Native.Z3_solver_translate(Context.nCtx, NativeObject, ctx.nCtx)); + } + + /// + /// Import model converter from other solver. + /// + public void ImportModelConverter(NativeSolver src) + { + Native.Z3_solver_import_model_converter(Context.nCtx, src.NativeObject, NativeObject); + } + +#if false + /// + /// Solver statistics. + /// + public Statistics Statistics + { + get + { + + return new Statistics(Context, Native.Z3_solver_get_statistics(Context.nCtx, NativeObject)); + } + } +#endif + + /// + /// A string representation of the solver. + /// + public override string ToString() + { + return Native.Z3_solver_to_string(Context.nCtx, NativeObject); + } + +#region Internal + NativeContext Context; + IntPtr NativeObject; + internal NativeSolver(NativeContext ctx, Z3_solver obj) + { + Context = ctx; + NativeObject = obj; + + Debug.Assert(ctx != null); + this.BacktrackLevel = uint.MaxValue; + Native.Z3_solver_inc_ref(ctx.nCtx, obj); + } + + /// + /// Finalizer. + /// + ~NativeSolver() + { + Dispose(); + } + + /// + /// Disposes of the underlying native Z3 object. + /// + public void Dispose() + { + if (NativeObject != IntPtr.Zero) + { + Native.Z3_solver_dec_ref(Context.nCtx, NativeObject); + NativeObject = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + + + private Status lboolToStatus(Z3_lbool r) + { + switch (r) + { + case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE; + case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE; + default: return Status.UNKNOWN; + } + } + +#endregion + } +} From 80506dfdfa80b4845f572c9773d7a7f6e3a95ef4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Mar 2022 10:55:39 -0800 Subject: [PATCH 087/258] sketch ArrayValue, add statistics Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 8 +++ src/api/dotnet/NativeModel.cs | 39 +++++++++++++ src/api/dotnet/NativeSolver.cs | 99 ++++----------------------------- src/api/dotnet/Statistics.cs | 39 +++++++------ 4 files changed, 81 insertions(+), 104 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index a13e48bf7..1aca7fe55 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -197,5 +197,13 @@ namespace Microsoft.Z3 } + public Statistics.Entry[] GetStatistics(Z3_stats stats) + { + Native.Z3_stats_inc_ref(nCtx, stats); + var result = Statistics.NativeEntries(nCtx, stats); + Native.Z3_stats_dec_ref(nCtx, stats); + return result; + } + } } \ No newline at end of file diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index fcb536a05..9e5cc44a1 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -39,6 +39,7 @@ namespace Microsoft.Z3 /// public class NativeModel : IDisposable { + /// /// Retrieves the interpretation (the assignment) of in the model. /// @@ -244,6 +245,44 @@ namespace Microsoft.Z3 return Native.Z3_get_numeral_double(Context.nCtx, r); } + /// + /// An array value obtained by untangling a model assignment. + /// + public class ArrayValue + { + /// + /// One dimensional array of indices where the array is updated + /// + public KeyValuePair[] Updates; + + /// + /// default Else case + /// + public Z3_ast Else; + } + + public ArrayValue TryGetArrayValue(Z3_ast t) + { + var r = Eval(t, true); + // check that r is a sequence of store over a constant default array. + var updates = new List>(); + var result = new ArrayValue(); + while (true) + { + // check that r is an app, and the decl-kind is Z3_OP_ARRAY_CONST or Z3_OP_ARRAY_STORE + // if it is Z3_OP_ARRAY_CONST then set result.Else and break; + // if it is ARRAY_STORE, then append to 'updates' and continue + // in other cases return null + return null; + + } +#if false + result.Updates = updates.ToArray(); + + return null; +#endif + } + /// /// The number of uninterpreted sorts that the model has an interpretation for. /// diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs index 0c494fa33..c500356da 100644 --- a/src/api/dotnet/NativeSolver.cs +++ b/src/api/dotnet/NativeSolver.cs @@ -32,8 +32,6 @@ namespace Microsoft.Z3 using Z3_sort = System.IntPtr; using Z3_func_decl = System.IntPtr; using Z3_model = System.IntPtr; - using Z3_func_interp = System.IntPtr; - using Z3_func_entry = System.IntPtr; using Z3_ast_vector = System.IntPtr; using Z3_solver = System.IntPtr; @@ -54,6 +52,7 @@ namespace Microsoft.Z3 } } +#if false /// /// Sets the solver parameters. /// @@ -67,7 +66,7 @@ namespace Microsoft.Z3 } } -#if false + /// /// Sets parameter on the solver /// @@ -252,11 +251,7 @@ namespace Microsoft.Z3 { get { - var assertions = Native.Z3_solver_get_assertions(Context.nCtx, NativeObject); - Native.Z3_ast_vector_inc_ref(Context.nCtx, assertions); - var sz = Native.Z3_ast_vector_size(Context.nCtx, assertions); - Native.Z3_ast_vector_dec_ref(Context.nCtx, assertions); - return sz; + return (uint)Context.ToArray(Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)).Length; } } @@ -267,8 +262,7 @@ namespace Microsoft.Z3 { get { - var assertions = Native.Z3_solver_get_assertions(Context.nCtx, NativeObject); - return Context.ToArray(assertions); + return Context.ToArray(Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); } } @@ -279,8 +273,7 @@ namespace Microsoft.Z3 { get { - var units = Native.Z3_solver_get_units(Context.nCtx, NativeObject); - return Context.ToArray(units); + return Context.ToArray(Native.Z3_solver_get_units(Context.nCtx, NativeObject)); } } @@ -321,34 +314,6 @@ namespace Microsoft.Z3 return lboolToStatus(r); } -#if false - /// - /// Retrieve fixed assignments to the set of variables in the form of consequences. - /// Each consequence is an implication of the form - /// - /// relevant-assumptions Implies variable = value - /// - /// where the relevant assumptions is a subset of the assumptions that are passed in - /// and the equality on the right side of the implication indicates how a variable - /// is fixed. - /// - /// - /// - /// - /// - /// - public Status Consequences(IEnumerable assumptions, IEnumerable variables, out Z3_ast[] consequences) - { - ASTVector result = new ASTVector(Context); - ASTVector asms = new ASTVector(Context); - ASTVector vars = new ASTVector(Context); - foreach (var asm in assumptions) asms.Push(asm); - foreach (var v in variables) vars.Push(v); - Z3_lbool r = (Z3_lbool)Native.Z3_solver_get_consequences(Context.nCtx, NativeObject, asms.NativeObject, vars.NativeObject, result.NativeObject); - consequences = result.ToBoolExprArray(); - return lboolToStatus(r); - } -#endif /// /// The model of the last Check(params Expr[] assumptions). @@ -411,46 +376,6 @@ namespace Microsoft.Z3 } } - /// - /// Backtrack level that can be adjusted by conquer process - /// - public uint BacktrackLevel { get; set; } - -#if false - /// - /// Variables available and returned by the cuber. - /// - public Z3_ast[] CubeVariables { get; set; } - - - /// - /// Return a set of cubes. - /// - public IEnumerable Cube() - { - ASTVector cv = new ASTVector(Context); - if (CubeVariables != null) - foreach (var b in CubeVariables) cv.Push(b); - - while (true) - { - var lvl = BacktrackLevel; - BacktrackLevel = uint.MaxValue; - ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl)); - var v = r.ToBoolExprArray(); - CubeVariables = cv.ToBoolExprArray(); - if (v.Length == 1 && v[0].IsFalse) - { - break; - } - yield return v; - if (v.Length == 0) - { - break; - } - } - } -#endif /// /// Create a clone of the current solver with respect to ctx. /// @@ -468,19 +393,18 @@ namespace Microsoft.Z3 Native.Z3_solver_import_model_converter(Context.nCtx, src.NativeObject, NativeObject); } -#if false + /// /// Solver statistics. /// - public Statistics Statistics + public Statistics.Entry[] Statistics { get { - - return new Statistics(Context, Native.Z3_solver_get_statistics(Context.nCtx, NativeObject)); + var stats = Native.Z3_solver_get_statistics(Context.nCtx, NativeObject); + return Context.GetStatistics(stats); } } -#endif /// /// A string representation of the solver. @@ -490,7 +414,7 @@ namespace Microsoft.Z3 return Native.Z3_solver_to_string(Context.nCtx, NativeObject); } -#region Internal + #region Internal NativeContext Context; IntPtr NativeObject; internal NativeSolver(NativeContext ctx, Z3_solver obj) @@ -499,7 +423,6 @@ namespace Microsoft.Z3 NativeObject = obj; Debug.Assert(ctx != null); - this.BacktrackLevel = uint.MaxValue; Native.Z3_solver_inc_ref(ctx.nCtx, obj); } @@ -535,6 +458,6 @@ namespace Microsoft.Z3 } } -#endregion + #endregion } } diff --git a/src/api/dotnet/Statistics.cs b/src/api/dotnet/Statistics.cs index 8b664913a..f6d72e0c7 100644 --- a/src/api/dotnet/Statistics.cs +++ b/src/api/dotnet/Statistics.cs @@ -23,6 +23,9 @@ using System.Diagnostics; namespace Microsoft.Z3 { + + using Z3_context = System.IntPtr; + using Z3_stats = System.IntPtr; /// /// Objects of this class track statistical information about solvers. /// @@ -123,25 +126,29 @@ namespace Microsoft.Z3 { get { - - uint n = Size; - Entry[] res = new Entry[n]; - for (uint i = 0; i < n; i++) - { - Entry e; - string k = Native.Z3_stats_get_key(Context.nCtx, NativeObject, i); - if (Native.Z3_stats_is_uint(Context.nCtx, NativeObject, i) != 0) - e = new Entry(k, Native.Z3_stats_get_uint_value(Context.nCtx, NativeObject, i)); - else if (Native.Z3_stats_is_double(Context.nCtx, NativeObject, i) != 0) - e = new Entry(k, Native.Z3_stats_get_double_value(Context.nCtx, NativeObject, i)); - else - throw new Z3Exception("Unknown data entry value"); - res[i] = e; - } - return res; + return NativeEntries(Context.nCtx, NativeObject); } } + internal static Entry[] NativeEntries(Z3_context ctx, Z3_stats stats) + { + uint n = Native.Z3_stats_size(ctx, stats); + Entry[] res = new Entry[n]; + for (uint i = 0; i < n; i++) + { + Entry e; + string k = Native.Z3_stats_get_key(ctx, stats, i); + if (Native.Z3_stats_is_uint(ctx, stats, i) != 0) + e = new Entry(k, Native.Z3_stats_get_uint_value(ctx, stats, i)); + else if (Native.Z3_stats_is_double(ctx, stats, i) != 0) + e = new Entry(k, Native.Z3_stats_get_double_value(ctx, stats, i)); + else + throw new Z3Exception("Unknown data entry value"); + res[i] = e; + } + return res; + } + /// /// The statistical counters. /// From 757cf7622d549d5280748464366092aa198a5def Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Mar 2022 10:59:19 -0800 Subject: [PATCH 088/258] sketch ArrayValue, add statistics Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 5 +++++ src/api/dotnet/NativeModel.cs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 1aca7fe55..a19e0c5af 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -197,6 +197,11 @@ namespace Microsoft.Z3 } + /// + /// Retrieve statistics as an array of entries + /// + /// + /// public Statistics.Entry[] GetStatistics(Z3_stats stats) { Native.Z3_stats_inc_ref(nCtx, stats); diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index 9e5cc44a1..417426b3b 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -261,6 +261,11 @@ namespace Microsoft.Z3 public Z3_ast Else; } + /// + /// Convert the interpretation of t into a sequence of array updates + /// + /// + /// null if the argument does evaluate to a sequence of stores to an array public ArrayValue TryGetArrayValue(Z3_ast t) { var r = Eval(t, true); From ee18c5070c279f8a04e2a5dd63ece0b86c452ea3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 09:09:03 -0800 Subject: [PATCH 089/258] add stubs for injective function axioms, add some parameter functions --- src/api/dotnet/NativeSolver.cs | 95 ++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 26 deletions(-) diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs index c500356da..74238692f 100644 --- a/src/api/dotnet/NativeSolver.cs +++ b/src/api/dotnet/NativeSolver.cs @@ -34,6 +34,8 @@ namespace Microsoft.Z3 using Z3_model = System.IntPtr; using Z3_ast_vector = System.IntPtr; using Z3_solver = System.IntPtr; + using Z3_symbol = System.IntPtr; + using Z3_params = System.IntPtr; /// /// Solvers. @@ -47,42 +49,52 @@ namespace Microsoft.Z3 { get { - return Native.Z3_solver_get_help(Context.nCtx, NativeObject); } } -#if false - /// - /// Sets the solver parameters. - /// - public Params Parameters + private void SetParam(Action setter) { - set - { - Debug.Assert(value != null); - - Native.Z3_solver_set_params(Context.nCtx, NativeObject, value.NativeObject); - } + Z3_params p = Native.Z3_mk_params(Context.nCtx); + Native.Z3_params_inc_ref(Context.nCtx, p); + setter(p); + Native.Z3_solver_set_params(Context.nCtx, NativeObject, p); + Native.Z3_params_dec_ref(Context.nCtx, p); } - /// /// Sets parameter on the solver /// - public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(string name, bool value) + { + SetParam((Z3_params p) => Native.Z3_params_set_bool(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), (byte)(value ? 1 : 0))); + } + + /// + /// Sets parameter on the solver + /// + public void Set(string name, uint value) + { + SetParam((Z3_params p) => Native.Z3_params_set_uint(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), value)); + } + + /// + /// Sets parameter on the solver + /// + public void Set(string name, double value) + { + SetParam((Z3_params p) => Native.Z3_params_set_double(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), value)); + } + + /// + /// Sets parameter on the solver + /// + public void Set(string name, string value) + { + var value_sym = Native.Z3_mk_string_symbol(Context.nCtx, value); + SetParam((Z3_params p) => Native.Z3_params_set_symbol(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), value_sym)); + } +#if false /// /// Sets parameter on the solver /// @@ -186,6 +198,37 @@ namespace Microsoft.Z3 Assert(constraints.ToArray()); } + /// + /// Add constraints to ensure the function f can only be injective. + /// + /// + public void AssertInjective(Z3_func_decl f) + { + uint arity = Native.Z3_get_arity(Context.nCtx, f); + Z3_sort range = Native.Z3_get_range(Context.nCtx, f); + Z3_ast[] vars = new Z3_ast[arity]; + Z3_sort[] sorts = new Z3_sort[arity]; + Z3_symbol[] names = new Z3_symbol[arity]; + for (uint i = 0; i < arity; ++i) + { + Z3_sort domain = Native.Z3_get_domain(Context.nCtx, f, i); + //vars[i] = Context.MkBound(arity - i - 1, domain); + sorts[i] = domain; + names[i] = Native.Z3_mk_int_symbol(Context.nCtx, (int)i); + } + Z3_ast app_f = IntPtr.Zero; // Context.MkApp(f, vars); + for (uint i = 0; i < arity; ++i) + { + Z3_sort domain = Native.Z3_get_domain(Context.nCtx, f, i); +#if false + Z3_func_decl proj = Native.Z3_mk_fresh_func_decl("inv", new Z3_sort[] { range }, domain); + Z3_ast body = Context.MkEq(vars[i], Context.MkApp(proj, app_f)); + Z3_ast q = Context.MkForall(names, sorts, body); + Assert(q); +#endif + } + } + /// /// Assert multiple constraints into the solver, and track them (in the unsat) core /// using the Boolean constants in ps. From 811cd9d48d98963be64e730e5a61a4b310bfee3a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 09:14:47 -0800 Subject: [PATCH 090/258] add example Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeSolver.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs index 74238692f..01e761e18 100644 --- a/src/api/dotnet/NativeSolver.cs +++ b/src/api/dotnet/NativeSolver.cs @@ -200,6 +200,11 @@ namespace Microsoft.Z3 /// /// Add constraints to ensure the function f can only be injective. + /// Example: + /// for function f : D1 x D2 -> R + /// assert axioms + /// forall (x1 : D1, x2 : D2) x1 = inv1(f(x1,x2)) + /// forall (x1 : D1, x2 : D2) x2 = inv2(f(x1,x2)) /// /// public void AssertInjective(Z3_func_decl f) From a08be497f7ae56bf5a5190eef353f5179b98f1e3 Mon Sep 17 00:00:00 2001 From: John Fleisher Date: Thu, 3 Mar 2022 13:41:12 -0500 Subject: [PATCH 091/258] NativeContext, NativeSolver, NativeModel - updates for Pex (#5878) * WiP: Disposable, MkAdd, MkApp, MkBool, MkBoolSort, MkBound, MkBvSort, MkFalse, MkTrue, MkIntSort * WiP: Native z3 mk_ functions * WiP: mk_ functions for NativeContext * WiP: add utility functions for getting values * WiP: Adding more native utility functions * native model pull * WiP: NativeContext additions for array access * WiP: use Z3_symbol in place of managed Symbol * WiP: add solver, model, and array methods * WiP: MkSimpleSolver, MkReal * WiP: GetDomain GetRange * WiP: MkExists * Override for MkFuncDecl * MkConstArray, MkSelect * WiP: code cleanup * migrate Context reference to NativeContext * remove local signing from PR * minor code cleanup Co-authored-by: jfleisher --- src/api/dotnet/Context.cs | 153 ++-- src/api/dotnet/NativeContext.cs | 1206 +++++++++++++++++++++++++++++-- src/api/dotnet/NativeModel.cs | 55 +- src/api/dotnet/NativeSolver.cs | 257 +++---- 4 files changed, 1361 insertions(+), 310 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 94b69d206..3432c8028 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -231,7 +231,6 @@ namespace Microsoft.Z3 return new BitVecSort(this, Native.Z3_mk_bv_sort(nCtx, size)); } - /// /// Create a new sequence sort. /// @@ -485,7 +484,7 @@ namespace Microsoft.Z3 /// The function performs a record update at t. The field /// that is passed in as argument is updated with value v, /// the remaining fields of t are unchanged. - /// + /// public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) { return Expr.Create(this, Native.Z3_datatype_update_field( @@ -560,14 +559,14 @@ namespace Microsoft.Z3 /// MkRecFuncDecl. The body may contain recursive uses of the function or /// other mutually recursive functions. /// - public void AddRecDef(FuncDecl f, Expr[] args, Expr body) - { - CheckContextMatch(f); - CheckContextMatch(args); - CheckContextMatch(body); + public void AddRecDef(FuncDecl f, Expr[] args, Expr body) + { + CheckContextMatch(f); + CheckContextMatch(args); + CheckContextMatch(body); IntPtr[] argsNative = AST.ArrayToNative(args); - Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject); - } + Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject); + } /// /// Creates a new function declaration. @@ -811,7 +810,7 @@ namespace Microsoft.Z3 public Expr MkApp(FuncDecl f, IEnumerable args) { Debug.Assert(f != null); - Debug.Assert(args == null || args.All( a => a != null)); + Debug.Assert(args == null || args.All(a => a != null)); CheckContextMatch(f); CheckContextMatch(args); @@ -949,14 +948,15 @@ namespace Microsoft.Z3 Debug.Assert(ts.All(a => a != null)); CheckContextMatch(ts); BoolExpr r = null; - foreach (var t in ts) { - if (r == null) - r = t; + foreach (var t in ts) + { + if (r == null) + r = t; else - r = MkXor(r, t); + r = MkXor(r, t); } - if (r == null) - r = MkTrue(); + if (r == null) + r = MkTrue(); return r; } @@ -2343,7 +2343,7 @@ namespace Microsoft.Z3 CheckContextMatch(elem); CheckContextMatch(set); - return (BoolExpr) Expr.Create(this, Native.Z3_mk_set_member(nCtx, elem.NativeObject, set.NativeObject)); + return (BoolExpr)Expr.Create(this, Native.Z3_mk_set_member(nCtx, elem.NativeObject, set.NativeObject)); } /// @@ -2356,7 +2356,7 @@ namespace Microsoft.Z3 CheckContextMatch(arg1); CheckContextMatch(arg2); - return (BoolExpr) Expr.Create(this, Native.Z3_mk_set_subset(nCtx, arg1.NativeObject, arg2.NativeObject)); + return (BoolExpr)Expr.Create(this, Native.Z3_mk_set_subset(nCtx, arg1.NativeObject, arg2.NativeObject)); } #endregion @@ -2366,7 +2366,7 @@ namespace Microsoft.Z3 /// /// Create the empty sequence. /// - public SeqExpr MkEmptySeq(Sort s) + public SeqExpr MkEmptySeq(Sort s) { Debug.Assert(s != null); return new SeqExpr(this, Native.Z3_mk_seq_empty(nCtx, s.NativeObject)); @@ -2375,7 +2375,7 @@ namespace Microsoft.Z3 /// /// Create the singleton sequence. /// - public SeqExpr MkUnit(Expr elem) + public SeqExpr MkUnit(Expr elem) { Debug.Assert(elem != null); return new SeqExpr(this, Native.Z3_mk_seq_unit(nCtx, elem.NativeObject)); @@ -2384,7 +2384,7 @@ namespace Microsoft.Z3 /// /// Create a string constant. /// - public SeqExpr MkString(string s) + public SeqExpr MkString(string s) { Debug.Assert(s != null); return new SeqExpr(this, Native.Z3_mk_string(nCtx, s)); @@ -2393,7 +2393,7 @@ namespace Microsoft.Z3 /// /// Convert an integer expression to a string. /// - public SeqExpr IntToString(Expr e) + public SeqExpr IntToString(Expr e) { Debug.Assert(e != null); Debug.Assert(e is ArithExpr); @@ -2413,7 +2413,8 @@ namespace Microsoft.Z3 /// /// Convert a bit-vector expression, represented as an signed number, to a string. /// - public SeqExpr SbvToString(Expr e) { + public SeqExpr SbvToString(Expr e) + { Debug.Assert(e != null); Debug.Assert(e is ArithExpr); return new SeqExpr(this, Native.Z3_mk_sbv_to_str(nCtx, e.NativeObject)); @@ -2422,7 +2423,7 @@ namespace Microsoft.Z3 /// /// Convert an integer expression to a string. /// - public IntExpr StringToInt(Expr e) + public IntExpr StringToInt(Expr e) { Debug.Assert(e != null); Debug.Assert(e is SeqExpr); @@ -2449,13 +2450,13 @@ namespace Microsoft.Z3 public IntExpr MkLength(SeqExpr s) { Debug.Assert(s != null); - return (IntExpr) Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject)); + return (IntExpr)Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject)); } /// /// Check for sequence prefix. /// - public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2) + public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2) { Debug.Assert(s1 != null); Debug.Assert(s2 != null); @@ -2466,7 +2467,7 @@ namespace Microsoft.Z3 /// /// Check for sequence suffix. /// - public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2) + public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2) { Debug.Assert(s1 != null); Debug.Assert(s2 != null); @@ -2477,7 +2478,7 @@ namespace Microsoft.Z3 /// /// Check for sequence containment of s2 in s1. /// - public BoolExpr MkContains(SeqExpr s1, SeqExpr s2) + public BoolExpr MkContains(SeqExpr s1, SeqExpr s2) { Debug.Assert(s1 != null); Debug.Assert(s2 != null); @@ -2488,7 +2489,7 @@ namespace Microsoft.Z3 /// /// Check if the string s1 is lexicographically strictly less than s2. /// - public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2) + public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2) { Debug.Assert(s1 != null); Debug.Assert(s2 != null); @@ -2499,7 +2500,7 @@ namespace Microsoft.Z3 /// /// Check if the string s1 is lexicographically less or equal to s2. /// - public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2) + public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2) { Debug.Assert(s1 != null); Debug.Assert(s2 != null); @@ -2568,10 +2569,10 @@ namespace Microsoft.Z3 /// /// Convert a regular expression that accepts sequence s. /// - public ReExpr MkToRe(SeqExpr s) + public ReExpr MkToRe(SeqExpr s) { Debug.Assert(s != null); - return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject)); + return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject)); } @@ -2583,7 +2584,7 @@ namespace Microsoft.Z3 Debug.Assert(s != null); Debug.Assert(re != null); CheckContextMatch(s, re); - return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject)); + return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject)); } /// @@ -2592,7 +2593,7 @@ namespace Microsoft.Z3 public ReExpr MkStar(ReExpr re) { Debug.Assert(re != null); - return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject)); + return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject)); } /// @@ -2601,7 +2602,7 @@ namespace Microsoft.Z3 public ReExpr MkLoop(ReExpr re, uint lo, uint hi = 0) { Debug.Assert(re != null); - return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi)); + return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi)); } /// @@ -2610,7 +2611,7 @@ namespace Microsoft.Z3 public ReExpr MkPlus(ReExpr re) { Debug.Assert(re != null); - return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject)); + return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject)); } /// @@ -2619,7 +2620,7 @@ namespace Microsoft.Z3 public ReExpr MkOption(ReExpr re) { Debug.Assert(re != null); - return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject)); + return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject)); } /// @@ -2628,7 +2629,7 @@ namespace Microsoft.Z3 public ReExpr MkComplement(ReExpr re) { Debug.Assert(re != null); - return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject)); + return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject)); } /// @@ -2670,7 +2671,7 @@ namespace Microsoft.Z3 /// /// Create a difference regular expression. /// - public ReExpr MkDiff(ReExpr a, ReExpr b) + public ReExpr MkDiff(ReExpr a, ReExpr b) { Debug.Assert(a != null); Debug.Assert(b != null); @@ -2682,7 +2683,7 @@ namespace Microsoft.Z3 /// Create the empty regular expression. /// The sort s should be a regular expression. /// - public ReExpr MkEmptyRe(Sort s) + public ReExpr MkEmptyRe(Sort s) { Debug.Assert(s != null); return new ReExpr(this, Native.Z3_mk_re_empty(nCtx, s.NativeObject)); @@ -2692,7 +2693,7 @@ namespace Microsoft.Z3 /// Create the full regular expression. /// The sort s should be a regular expression. /// - public ReExpr MkFullRe(Sort s) + public ReExpr MkFullRe(Sort s) { Debug.Assert(s != null); return new ReExpr(this, Native.Z3_mk_re_full(nCtx, s.NativeObject)); @@ -2702,7 +2703,7 @@ namespace Microsoft.Z3 /// /// Create a range expression. /// - public ReExpr MkRange(SeqExpr lo, SeqExpr hi) + public ReExpr MkRange(SeqExpr lo, SeqExpr hi) { Debug.Assert(lo != null); Debug.Assert(hi != null); @@ -2713,7 +2714,7 @@ namespace Microsoft.Z3 /// /// Create less than or equal to between two characters. /// - public BoolExpr MkCharLe(Expr ch1, Expr ch2) + public BoolExpr MkCharLe(Expr ch1, Expr ch2) { Debug.Assert(ch1 != null); Debug.Assert(ch2 != null); @@ -2723,7 +2724,7 @@ namespace Microsoft.Z3 /// /// Create an integer (code point) from character. /// - public IntExpr CharToInt(Expr ch) + public IntExpr CharToInt(Expr ch) { Debug.Assert(ch != null); return new IntExpr(this, Native.Z3_mk_char_to_int(nCtx, ch.NativeObject)); @@ -2732,7 +2733,7 @@ namespace Microsoft.Z3 /// /// Create a bit-vector (code point) from character. /// - public BitVecExpr CharToBV(Expr ch) + public BitVecExpr CharToBV(Expr ch) { Debug.Assert(ch != null); return new BitVecExpr(this, Native.Z3_mk_char_to_bv(nCtx, ch.NativeObject)); @@ -2741,7 +2742,7 @@ namespace Microsoft.Z3 /// /// Create a character from a bit-vector (code point). /// - public Expr CharFromBV(BitVecExpr bv) + public Expr CharFromBV(BitVecExpr bv) { Debug.Assert(bv != null); return new Expr(this, Native.Z3_mk_char_from_bv(nCtx, bv.NativeObject)); @@ -2750,7 +2751,7 @@ namespace Microsoft.Z3 /// /// Create a check if the character is a digit. /// - public BoolExpr MkIsDigit(Expr ch) + public BoolExpr MkIsDigit(Expr ch) { Debug.Assert(ch != null); return new BoolExpr(this, Native.Z3_mk_char_is_digit(nCtx, ch.NativeObject)); @@ -2768,7 +2769,7 @@ namespace Microsoft.Z3 Debug.Assert(args != null); CheckContextMatch(args); var ts = args.ToArray(); - return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) ts.Length, + return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint)ts.Length, AST.ArrayToNative(ts), k)); } @@ -2780,7 +2781,7 @@ namespace Microsoft.Z3 Debug.Assert(args != null); CheckContextMatch(args); var ts = args.ToArray(); - return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint) ts.Length, + return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint)ts.Length, AST.ArrayToNative(ts), k)); } @@ -2789,13 +2790,13 @@ namespace Microsoft.Z3 /// public BoolExpr MkPBLe(int[] coeffs, BoolExpr[] args, int k) { - Debug.Assert(args != null); - Debug.Assert(coeffs != null); - Debug.Assert(args.Length == coeffs.Length); - CheckContextMatch(args); - return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint) args.Length, - AST.ArrayToNative(args), - coeffs, k)); + Debug.Assert(args != null); + Debug.Assert(coeffs != null); + Debug.Assert(args.Length == coeffs.Length); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint)args.Length, + AST.ArrayToNative(args), + coeffs, k)); } /// @@ -2803,26 +2804,26 @@ namespace Microsoft.Z3 /// public BoolExpr MkPBGe(int[] coeffs, BoolExpr[] args, int k) { - Debug.Assert(args != null); - Debug.Assert(coeffs != null); - Debug.Assert(args.Length == coeffs.Length); - CheckContextMatch(args); - return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint) args.Length, - AST.ArrayToNative(args), - coeffs, k)); + Debug.Assert(args != null); + Debug.Assert(coeffs != null); + Debug.Assert(args.Length == coeffs.Length); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint)args.Length, + AST.ArrayToNative(args), + coeffs, k)); } /// /// Create a pseudo-Boolean equal constraint. /// public BoolExpr MkPBEq(int[] coeffs, BoolExpr[] args, int k) { - Debug.Assert(args != null); - Debug.Assert(coeffs != null); - Debug.Assert(args.Length == coeffs.Length); - CheckContextMatch(args); - return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint) args.Length, - AST.ArrayToNative(args), - coeffs, k)); + Debug.Assert(args != null); + Debug.Assert(coeffs != null); + Debug.Assert(args.Length == coeffs.Length); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint)args.Length, + AST.ArrayToNative(args), + coeffs, k)); } #endregion @@ -4085,7 +4086,7 @@ namespace Microsoft.Z3 /// indicates whether the result should be negative. public FPNum MkFPZero(FPSort s, bool negative) { - return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, (byte)(negative ? 1 : 0))); + return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, (byte)(negative ? 1 : 0))); } /// @@ -4127,7 +4128,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(bool sgn, uint sig, int exp, FPSort s) { - return new FPNum(this, Native.Z3_mk_fpa_numeral_int_uint(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject)); + return new FPNum(this, Native.Z3_mk_fpa_numeral_int_uint(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject)); } /// @@ -4139,7 +4140,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(bool sgn, Int64 exp, UInt64 sig, FPSort s) { - return new FPNum(this, Native.Z3_mk_fpa_numeral_int64_uint64(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject)); + return new FPNum(this, Native.Z3_mk_fpa_numeral_int64_uint64(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject)); } /// @@ -4825,12 +4826,12 @@ namespace Microsoft.Z3 /// /// ASTVector DRQ /// - public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } } + public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } } /// /// ApplyResult DRQ /// - public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } } + public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } } /// /// FuncEntry DRQ @@ -4937,7 +4938,7 @@ namespace Microsoft.Z3 m_ctx = IntPtr.Zero; Native.Z3_del_context(ctx); } - else + else GC.ReRegisterForFinalize(this); } #endregion diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index a19e0c5af..42a9bab90 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -1,48 +1,55 @@ -using System; -using System.Diagnostics; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Linq; - namespace Microsoft.Z3 { - using Z3_symbol = System.IntPtr; - using Z3_config = System.IntPtr; - using Z3_context = System.IntPtr; - using Z3_ast = System.IntPtr; using Z3_app = System.IntPtr; - using Z3_sort = System.IntPtr; + using Z3_ast = System.IntPtr; + using Z3_ast_vector = System.IntPtr; using Z3_func_decl = System.IntPtr; using Z3_pattern = System.IntPtr; - using Z3_model = System.IntPtr; - using Z3_literals = System.IntPtr; - using Z3_constructor = System.IntPtr; - using Z3_constructor_list = System.IntPtr; using Z3_solver = System.IntPtr; - using Z3_solver_callback = System.IntPtr; - using Z3_goal = System.IntPtr; - using Z3_tactic = System.IntPtr; - using Z3_params = System.IntPtr; - using Z3_probe = System.IntPtr; + using Z3_sort = System.IntPtr; using Z3_stats = System.IntPtr; - using Z3_ast_vector = System.IntPtr; - using Z3_ast_map = System.IntPtr; - using Z3_apply_result = System.IntPtr; - using Z3_func_interp = System.IntPtr; - using Z3_func_entry = System.IntPtr; - using Z3_fixedpoint = System.IntPtr; - using Z3_optimize = System.IntPtr; - using Z3_param_descrs = System.IntPtr; - using Z3_rcf_num = System.IntPtr; + using Z3_symbol = System.IntPtr; /// /// The main interaction with Z3 happens via the Context. /// NativeContext allows for efficient wrapper-reduced interaction with Z3 /// expressions. /// - - public class NativeContext + public class NativeContext : IDisposable { + /// + /// Constructor. + /// + /// + /// The following parameters can be set: + /// - proof (Boolean) Enable proof generation + /// - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting + /// - trace (Boolean) Tracing support for VCC + /// - trace_file_name (String) Trace out file for VCC traces + /// - timeout (unsigned) default timeout (in milliseconds) used for solvers + /// - well_sorted_check type checker + /// - auto_config use heuristics to automatically select solver and configure it + /// - model model generation for solvers, this parameter can be overwritten when creating a solver + /// - model_validate validate models produced by solvers + /// - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver + /// Note that in previous versions of Z3, this constructor was also used to set global and module parameters. + /// For this purpose we should now use + /// + public NativeContext(Dictionary settings) + : base() + { + Debug.Assert(settings != null); + + lock (creation_lock) + { + IntPtr cfg = Native.Z3_mk_config(); + foreach (KeyValuePair kv in settings) + Native.Z3_set_param_value(cfg, kv.Key, kv.Value); + m_ctx = Native.Z3_mk_context_rc(cfg); + Native.Z3_del_config(cfg); + InitContext(); + } + } #region Arithmetic /// @@ -53,9 +60,669 @@ namespace Microsoft.Z3 { Debug.Assert(t != null); Debug.Assert(t.All(a => a != IntPtr.Zero)); - return Native.Z3_mk_add(nCtx, (uint)t.Length, t); + + return Native.Z3_mk_add(nCtx, (uint)(t?.Length ?? 0), t); } + /// + /// Create an expression representing t[0] * t[1] * .... + /// + public Z3_ast MkMul(params Z3_ast[] t) + { + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != IntPtr.Zero)); + + var ts = t.ToArray(); + return Native.Z3_mk_mul(nCtx, (uint)(ts?.Length ?? 0), ts); + } + + /// + /// Create an expression representing t1 / t2. + /// + public Z3_ast MkDiv(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_div(nCtx, t1, t2); + } + + /// + /// Create an expression representing t1 <= t2 + /// + public Z3_ast MkLe(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_le(nCtx, t1, t2); + } + + /// + /// Create an expression representing t1 < t2 + /// + public Z3_ast MkLt(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_lt(nCtx, t1, t2); + } + + /// + /// Create an expression representing t1 >= t2 + /// + public Z3_ast MkGe(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_ge(nCtx, t1, t2); + } + + /// + /// Create an expression representing t1 > t2 + /// + public Z3_ast MkGt(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_gt(nCtx, t1, t2); + } + + /// + /// Unsigned less-than + /// + /// + /// The arguments must have the same bit-vector sort. + /// + public Z3_ast MkBvUlt(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvult(nCtx, t1, t2); + } + + /// + /// Unsigned less-than-equal + /// + /// + /// The arguments must have the same bit-vector sort. + /// + public Z3_ast MkBvUle(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvule(nCtx, t1, t2); + } + + /// + /// Creates the equality = . + /// + public Z3_ast MkEq(Z3_ast x, Z3_ast y) + { + Debug.Assert(x != IntPtr.Zero); + Debug.Assert(y != IntPtr.Zero); + + return Native.Z3_mk_eq(nCtx, x, y); + } + + /// + /// Mk an expression representing not(a). + /// + public Z3_ast MkNot(Z3_ast a) + { + Debug.Assert(a != IntPtr.Zero); + + return Native.Z3_mk_not(nCtx, a); + } + + /// + /// Create an expression representing t[0] and t[1] and .... + /// + public Z3_ast MkAnd(params Z3_ast[] t) + { + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != IntPtr.Zero)); + + return Native.Z3_mk_and(nCtx, (uint)(t?.Length ?? 0), t); + } + + /// + /// Create an expression representing t[0] or t[1] or .... + /// + public Z3_ast MkOr(params Z3_ast[] t) + { + Debug.Assert(t != null); + Debug.Assert(t.All(a => a != IntPtr.Zero)); + + return Native.Z3_mk_or(nCtx, (uint)(t?.Length ?? 0), t); + } + + + /// + /// Create a real numeral. + /// + /// A string representing the Term value in decimal notation. + /// A Term with value and sort Real + public Z3_ast MkReal(string v, Z3_sort realSort) + { + Debug.Assert(!string.IsNullOrEmpty(v)); + + return Native.Z3_mk_numeral(nCtx, v, realSort); + } + + /// + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. + /// + /// Value of the numeral + /// Sort of the numeral + public Z3_ast MkNumeral(int v, Z3_sort sort) + { + Debug.Assert(sort != IntPtr.Zero); + + return Native.Z3_mk_int(nCtx, v, sort); + } + + /// + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. + /// + /// Value of the numeral + /// Sort of the numeral + public Z3_ast MkNumeral(uint v, Z3_sort sort) + { + Debug.Assert(sort != null); + + return Native.Z3_mk_unsigned_int(nCtx, v, sort); + } + + /// + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. + /// + /// Value of the numeral + /// Sort of the numeral + public Z3_ast MkNumeral(long v, Z3_sort sort) + { + Debug.Assert(sort != null); + + return Native.Z3_mk_int64(nCtx, v, sort); + } + + /// + /// Create an expression representing an if-then-else: ite(t1, t2, t3). + /// + /// An expression with Boolean sort + /// An expression + /// An expression with the same sort as + public Z3_ast MkIte(Z3_ast t1, Z3_ast t2, Z3_ast t3) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + Debug.Assert(t3 != IntPtr.Zero); + + return Native.Z3_mk_ite(nCtx, t1, t2, t3); + } + + /// + /// Create an expression representing t1 -> t2. + /// + public Z3_ast MkImplies(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_implies(nCtx, t1, t2); + } + + #endregion + + #region Sort + + public Z3_sort MkIntSort() => Native.Z3_mk_int_sort(nCtx); + public Z3_sort MkBoolSort() => Native.Z3_mk_bool_sort(nCtx); + public Z3_sort MkBvSort(uint size) => Native.Z3_mk_bv_sort(nCtx, size); + public Z3_sort MkRealSort() => Native.Z3_mk_real_sort(nCtx); + + public Z3_sort MkListSort(string name, Z3_sort elemSort, + out Z3_func_decl inil, out Z3_func_decl iisnil, + out Z3_func_decl icons, out Z3_func_decl iiscons, + out Z3_func_decl ihead, out Z3_func_decl itail) + { + Debug.Assert(!string.IsNullOrEmpty(name)); + Debug.Assert(elemSort != IntPtr.Zero); + + IntPtr nil = IntPtr.Zero, isnil = IntPtr.Zero, + cons = IntPtr.Zero, iscons = IntPtr.Zero, + head = IntPtr.Zero, tail = IntPtr.Zero; + + var symbol = Native.Z3_mk_string_symbol(nCtx, name); + var sort = Native.Z3_mk_list_sort(nCtx, symbol, elemSort, + ref nil, ref isnil, ref cons, ref iscons, ref head, ref tail); + + inil = nil; + iisnil = isnil; + icons = cons; + iiscons = iscons; + ihead = head; + itail = tail; + + return sort; + } + + /// + /// Create a new array sort. + /// + public Z3_sort MkArraySort(Z3_sort domain, Z3_sort range) + { + Debug.Assert(domain != IntPtr.Zero); + Debug.Assert(range != IntPtr.Zero); + + return Native.Z3_mk_array_sort(nCtx, domain, range); + } + + /// + /// Create a new tuple sort. + /// + public Z3_sort MkTupleSort(Z3_symbol name, Z3_symbol[] fieldNames, Z3_sort[] fieldSorts, out Z3_func_decl constructor, Z3_func_decl[] projections) + { + Debug.Assert(name != IntPtr.Zero); + Debug.Assert(fieldNames != null); + Debug.Assert(fieldNames.All(fn => fn != IntPtr.Zero)); + Debug.Assert(fieldSorts == null || fieldSorts.All(fs => fs != IntPtr.Zero)); + + var numFields = (uint)(fieldNames?.Length ?? 0); + constructor = IntPtr.Zero; + return Native.Z3_mk_tuple_sort(nCtx, name, numFields, fieldNames, fieldSorts, ref constructor, projections); + } + + #endregion + + #region Propositional + /// + /// The true Term. + /// + public Z3_ast MkTrue() => Native.Z3_mk_true(nCtx); + + /// + /// The false Term. + /// + public Z3_ast MkFalse() => Native.Z3_mk_false(nCtx); + + /// + /// Creates a Boolean value. + /// + public Z3_ast MkBool(bool value) + { + + return value ? MkTrue() : MkFalse(); + } + + /// + /// Create an expression representing t1 iff t2. + /// + public Z3_ast MkIff(Z3_ast t1, Z3_ast t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_iff(nCtx, t1, t2); + } + #endregion + + #region Constants + /// + /// Creates a new Constant of sort and named . + /// + public Z3_ast MkConst(string name, Z3_sort range) + { + Debug.Assert(!string.IsNullOrEmpty(name)); + Debug.Assert(range != IntPtr.Zero); + + return Native.Z3_mk_const(nCtx, MkStringSymbol(name), range); + } + + #endregion + + #region Symbol + public Z3_symbol MkStringSymbol(string name) + { + Debug.Assert(!string.IsNullOrEmpty(name)); + + return Native.Z3_mk_string_symbol(nCtx, name); + } + #endregion + + #region Terms + /// + /// Create a new function application. + /// + public Z3_ast MkApp(Z3_func_decl f, params Z3_ast[] args) + { + Debug.Assert(f != IntPtr.Zero); + Debug.Assert(args == null || args.All(a => a != IntPtr.Zero)); + + return Native.Z3_mk_app(nCtx, f, (uint)(args?.Length ?? 0), args); + } + + #endregion + + #region Bound Variables + /// + /// Creates a new bound variable. + /// + /// The de-Bruijn index of the variable + /// The sort of the variable + public Z3_ast MkBound(uint index, Z3_sort sort) + { + Debug.Assert(sort != IntPtr.Zero); + + return Native.Z3_mk_bound(nCtx, index, sort); + } + #endregion + + #region Bit-vectors + /// + /// Bitwise conjunction. + /// + /// The arguments must have a bit-vector sort. + public Z3_ast_vector MkBvAnd(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvand(nCtx, t1, t2); + } + + /// + /// Bitwise negation. + /// + /// The argument must have a bit-vector sort. + public Z3_ast_vector MkBvNot(Z3_ast_vector t) + { + Debug.Assert(t != IntPtr.Zero); + + return Native.Z3_mk_bvnot(nCtx, t); + } + + /// + /// Standard two's complement unary minus. + /// + /// The arguments must have a bit-vector sort. + public Z3_ast_vector MkBvNeg(Z3_ast_vector t) + { + Debug.Assert(t != IntPtr.Zero); + + return Native.Z3_mk_bvneg(nCtx, t); + } + + /// + /// Standard two's complement unary minus. + /// + /// The arguments must have a bit-vector sort. + public Z3_ast_vector MkBVNeg(Z3_ast_vector t) + { + Debug.Assert(t != IntPtr.Zero); + + return Native.Z3_mk_bvneg(nCtx, t); + } + + /// + /// Two's complement addition. + /// + /// The arguments must have the same bit-vector sort. + public Z3_ast_vector MkBvAdd(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvadd(nCtx, t1, t2); + } + + /// + /// Bit-vector extraction. + /// + /// + /// Extract the bits down to from a bitvector of + /// size m to yield a new bitvector of size n, where + /// n = high - low + 1. + /// The argument must have a bit-vector sort. + /// + public Z3_ast_vector MkBvExtract(uint high, uint low, Z3_ast_vector t) + { + Debug.Assert(t != IntPtr.Zero); + + return Native.Z3_mk_extract(nCtx, high, low, t); + } + + /// + /// Bit-vector sign extension. + /// + /// + /// Sign-extends the given bit-vector to the (signed) equivalent bitvector of + /// size m+i, where \c m is the size of the given bit-vector. + /// The argument must have a bit-vector sort. + /// + public Z3_ast_vector MkBvSignExt(uint i, Z3_ast_vector t) + { + Debug.Assert(t != IntPtr.Zero); + + return Native.Z3_mk_sign_ext(nCtx, i, t); + } + + /// + /// Bit-vector zero extension. + /// + /// + /// Extend the given bit-vector with zeros to the (unsigned) equivalent + /// bitvector of size m+i, where \c m is the size of the + /// given bit-vector. + /// The argument must have a bit-vector sort. + /// + public Z3_ast_vector MkBvZeroExt(uint i, Z3_ast_vector t) + { + Debug.Assert(t != IntPtr.Zero); + + return Native.Z3_mk_zero_ext(nCtx, i, t); + } + + /// + /// Shift left. + /// + /// + /// It is equivalent to multiplication by 2^x where \c x is the value of . + /// + /// NB. The semantics of shift operations varies between environments. This + /// definition does not necessarily capture directly the semantics of the + /// programming language or assembly architecture you are modeling. + /// + /// The arguments must have a bit-vector sort. + /// + public Z3_ast_vector MkBvShl(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvshl(nCtx, t1, t2); + } + + /// + /// Logical shift right + /// + /// + /// It is equivalent to unsigned division by 2^x where \c x is the value of . + /// + /// NB. The semantics of shift operations varies between environments. This + /// definition does not necessarily capture directly the semantics of the + /// programming language or assembly architecture you are modeling. + /// + /// The arguments must have a bit-vector sort. + /// + public Z3_ast_vector MkBvLshr(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvlshr(nCtx, t1, t2); + } + + /// + /// Arithmetic shift right + /// + /// + /// It is like logical shift right except that the most significant + /// bits of the result always copy the most significant bit of the + /// second argument. + /// + /// NB. The semantics of shift operations varies between environments. This + /// definition does not necessarily capture directly the semantics of the + /// programming language or assembly architecture you are modeling. + /// + /// The arguments must have a bit-vector sort. + /// + public Z3_ast_vector MkBvAshr(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvashr(nCtx, t1, t2); + } + + /// + /// Two's complement signed less-than + /// + /// + /// The arguments must have the same bit-vector sort. + /// + public Z3_ast MkBvSlt(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvslt(nCtx, t1, t2); + } + + /// + /// Two's complement multiplication. + /// + /// The arguments must have the same bit-vector sort. + public Z3_ast_vector MkBvMul(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvmul(nCtx, t1, t2); + } + + /// + /// Unsigned division. + /// + /// + /// It is defined as the floor of t1/t2 if \c t2 is + /// different from zero. If t2 is zero, then the result + /// is undefined. + /// The arguments must have the same bit-vector sort. + /// + public Z3_ast_vector MkBvUdiv(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvudiv(nCtx, t1, t2); + } + + /// + /// Signed division. + /// + /// + /// It is defined in the following way: + /// + /// - The \c floor of t1/t2 if \c t2 is different from zero, and t1*t2 >= 0. + /// + /// - The \c ceiling of t1/t2 if \c t2 is different from zero, and t1*t2 < 0. + /// + /// If t2 is zero, then the result is undefined. + /// The arguments must have the same bit-vector sort. + /// + public Z3_ast_vector MkBvSdiv(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvsdiv(nCtx, t1, t2); + } + + /// + /// Unsigned remainder. + /// + /// + /// It is defined as t1 - (t1 /u t2) * t2, where /u represents unsigned division. + /// If t2 is zero, then the result is undefined. + /// The arguments must have the same bit-vector sort. + /// + public Z3_ast_vector MkBvUrem(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvurem(nCtx, t1, t2); + } + + /// + /// Signed remainder. + /// + /// + /// It is defined as t1 - (t1 /s t2) * t2, where /s represents signed division. + /// The most significant bit (sign) of the result is equal to the most significant bit of \c t1. + /// + /// If t2 is zero, then the result is undefined. + /// The arguments must have the same bit-vector sort. + /// + public Z3_ast_vector MkBvSrem(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvsrem(nCtx, t1, t2); + } + + /// + /// Two's complement subtraction. + /// + /// The arguments must have the same bit-vector sort. + public Z3_ast_vector MkBvSub(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvsub(nCtx, t1, t2); + } + + /// + /// Bitwise disjunction. + /// + /// The arguments must have a bit-vector sort. + public Z3_ast_vector MkBvOr(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != IntPtr.Zero); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvor(nCtx, t1, t2); + } + + /// + /// Bitwise XOR. + /// + /// The arguments must have a bit-vector sort. + public Z3_ast_vector MkBvXor(Z3_ast_vector t1, Z3_ast_vector t2) + { + Debug.Assert(t1 != null); + Debug.Assert(t2 != IntPtr.Zero); + + return Native.Z3_mk_bvxor(nCtx, t1, t2); + } #endregion #region Quantifiers @@ -83,11 +750,16 @@ namespace Microsoft.Z3 /// array containing the anti-patterns created using MkPattern. /// optional symbol to track quantifier. /// optional symbol to track skolem constants. - public Z3_ast MkForall(Z3_sort[] sorts, Symbol[] names, Z3_ast body, uint weight = 1, Z3_ast[] patterns = null, Z3_ast[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) + public Z3_ast MkForall(Z3_sort[] sorts, Z3_symbol[] names, Z3_ast body, uint weight = 1, Z3_ast[] patterns = null, Z3_ast[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { return MkQuantifier(true, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); } + public Z3_ast MkExists(Z3_sort[] sorts, Z3_symbol[] names, Z3_ast body, uint weight = 1, Z3_ast[] patterns = null, Z3_ast[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) + { + return MkQuantifier(false, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); + } + /// /// Create a quantified expression either forall or exists /// @@ -101,34 +773,33 @@ namespace Microsoft.Z3 /// /// /// - private Z3_ast MkQuantifier(bool is_forall, Z3_sort[] sorts, Symbol[] names, Z3_ast body, uint weight, Z3_ast[] patterns, Z3_ast[] noPatterns, Symbol quantifierID, Symbol skolemID) + private Z3_ast MkQuantifier(bool is_forall, Z3_sort[] sorts, Z3_symbol[] names, Z3_ast body, uint weight, Z3_ast[] patterns, Z3_ast[] noPatterns, Symbol quantifierID, Symbol skolemID) { Debug.Assert(sorts != null); Debug.Assert(names != null); Debug.Assert(body != null); Debug.Assert(sorts.Length == names.Length); Debug.Assert(sorts.All(s => s != IntPtr.Zero)); - Debug.Assert(names.All(n => n != null)); + Debug.Assert(names.All(n => n != IntPtr.Zero)); Debug.Assert(patterns == null || patterns.All(p => p != IntPtr.Zero)); Debug.Assert(noPatterns == null || noPatterns.All(np => np != IntPtr.Zero)); - uint numPatterns = patterns == null ? 0 : (uint)patterns.Length; - uint numNoPatterns = noPatterns == null ? 0 : (uint)noPatterns.Length; + if (noPatterns == null && quantifierID == null && skolemID == null) { return Native.Z3_mk_quantifier(nCtx, (byte)(is_forall ? 1 : 0), weight, - numPatterns, patterns, - (uint)sorts.Length, sorts, - Symbol.ArrayToNative(names), + (uint)(patterns?.Length ?? 0), patterns, + (uint)(sorts?.Length ?? 0), sorts, + names, body); } else { return Native.Z3_mk_quantifier_ex(nCtx, (byte)(is_forall ? 1 : 0), weight, AST.GetNativeObject(quantifierID), AST.GetNativeObject(skolemID), - numPatterns, patterns, - numNoPatterns, noPatterns, - (uint)sorts.Length, sorts, - Symbol.ArrayToNative(names), + (uint)(patterns?.Length ?? 0), patterns, + (uint)(noPatterns?.Length ?? 0), noPatterns, + (uint)(sorts?.Length ?? 0), sorts, + names, body); } } @@ -156,10 +827,421 @@ namespace Microsoft.Z3 { set { Native.Z3_set_ast_print_mode(nCtx, (uint)value); } } + #endregion + #region Arrays + + + /// + /// Create a constant array. + /// + /// + /// The resulting term is an array, such that a selecton an arbitrary index + /// produces the value v. + /// + public Z3_ast MkConstArray(Z3_sort domain, Z3_ast v) + { + Debug.Assert(domain != IntPtr.Zero); + Debug.Assert(v != IntPtr.Zero); + + return Native.Z3_mk_const_array(nCtx, domain, v); + } + + /// + /// Array update. + /// + /// + /// The node a must have an array sort [domain -> range], + /// i must have sort domain, + /// v must have sort range. The sort of the result is [domain -> range]. + /// The semantics of this function is given by the theory of arrays described in the SMT-LIB + /// standard. See http://smtlib.org for more details. + /// The result of this function is an array that is equal to a + /// (with respect to select) + /// on all indices except for i, where it maps to v + /// (and the select of a with + /// respect to i may be a different value). + /// + public Z3_ast MkStore(Z3_ast a, Z3_ast i, Z3_ast v) + { + Debug.Assert(a != IntPtr.Zero); + Debug.Assert(i != IntPtr.Zero); + Debug.Assert(v != IntPtr.Zero); + + return Native.Z3_mk_store(nCtx, a, i, v); + } + + /// + /// Array read. + /// + /// + /// The argument array is the array and index is the index + /// of the array that gets read. + /// + /// The node array must have an array sort [domain -> range], + /// and index must have the sort domain. + /// The sort of the result is range. + /// + public Z3_ast MkSelect(Z3_ast array, Z3_ast index) + { + Debug.Assert(array != IntPtr.Zero); + Debug.Assert(index != IntPtr.Zero); + + return Native.Z3_mk_select(nCtx, array, index); + } + + /// + /// Access the array default value. + /// + /// + /// Produces the default range value, for arrays that can be represented as + /// finite maps with a default range value. + /// + public Z3_ast MkDefault(Z3_ast a) + { + Debug.Assert(a != null); + + return Native.Z3_mk_array_default(nCtx, a); + } + + #endregion + + #region Function Declarations + + /// + /// Creates a new function declaration. + /// + public Z3_func_decl MkFuncDecl(string name, Z3_sort[] domain, Z3_sort range) + { + Debug.Assert(!string.IsNullOrEmpty(name)); + Debug.Assert(range != IntPtr.Zero); + Debug.Assert(domain != null); + Debug.Assert(domain.All(d => d != IntPtr.Zero)); + + var symbol = Native.Z3_mk_string_symbol(nCtx, name); + return Native.Z3_mk_func_decl(nCtx, symbol, (uint)(domain?.Length ?? 0), domain, range); + } + + /// + /// Creates a new function declaration. + /// + public Z3_func_decl MkFuncDecl(string name, Z3_sort domain, Z3_sort range) + { + Debug.Assert(!string.IsNullOrEmpty(name)); + Debug.Assert(range != IntPtr.Zero); + Debug.Assert(domain != IntPtr.Zero); + + var symbol = Native.Z3_mk_string_symbol(nCtx, name); + var q = new Z3_sort[] { domain }; + return Native.Z3_mk_func_decl(nCtx, symbol, (uint)q.Length, q, range); + } + + /// + /// Creates a fresh function declaration with a name prefixed with . + /// + public Z3_func_decl MkFreshFuncDecl(string prefix, Z3_sort[] domain, Z3_sort range) + { + Debug.Assert(domain != null); + Debug.Assert(range != IntPtr.Zero); + Debug.Assert(domain.All(d => d != IntPtr.Zero)); + + return Native.Z3_mk_fresh_func_decl(nCtx, prefix, (uint)(domain?.Length ?? 0), domain, range); + } + + /// + /// Creates a new constant function declaration. + /// + public Z3_func_decl MkConstDecl(string name, Z3_sort range) + { + Debug.Assert(range != IntPtr.Zero); + + var symbol = Native.Z3_mk_string_symbol(nCtx, name); + return Native.Z3_mk_func_decl(nCtx, symbol, 0, new IntPtr[0], range); + } + + /// + /// Get domain for a funcdecl + /// + /// + /// + public Z3_sort[] GetDomain(Z3_func_decl fdecl) + { + Debug.Assert(fdecl != IntPtr.Zero); + + var sz = Native.Z3_get_domain_size(nCtx, fdecl); + var domain = new Z3_sort[sz]; + for (uint i = 0; i < sz; i++) + { + domain[i] = Native.Z3_get_domain(nCtx, fdecl, i); + } + return domain; + } + + /// + /// Get range for a funcdecl + /// + /// + /// + public Z3_sort GetRange(Z3_func_decl fdecl) + { + Debug.Assert(fdecl != IntPtr.Zero); + + return Native.Z3_get_range(nCtx, fdecl); + } + + #endregion + + #region Quantifier Patterns + /// + /// Create a quantifier pattern. + /// + public Z3_pattern MkPattern(params Z3_ast[] terms) + { + Debug.Assert(terms != null); + if (terms == null || terms.Length == 0) + throw new Z3Exception("Cannot create a pattern from zero terms"); + + return Native.Z3_mk_pattern(nCtx, (uint)terms.Length, terms); + } + #endregion + + #region Solver + + /// + /// Creates a new (incremental) solver. + /// + public NativeSolver MkSimpleSolver() + { + Z3_solver nSolver = Native.Z3_mk_simple_solver(nCtx); + return new NativeSolver(this, nSolver); + } + + #endregion + + #region Utilities + /// + /// Get the sort kind from IntPtr + /// + public Z3_sort_kind GetSortKind(Z3_sort sort) + { + Debug.Assert(sort != IntPtr.Zero); + + return (Z3_sort_kind)Native.Z3_get_sort_kind(nCtx, sort); + } + + /// + /// Get the AST kind from IntPtr + /// + public Z3_ast_kind GetAstKind(Z3_ast ast) + { + Debug.Assert(ast != IntPtr.Zero); + + return (Z3_ast_kind)Native.Z3_get_ast_kind(nCtx, ast); + } + + /// + /// Get the Decl kind from IntPtr + /// + public Z3_decl_kind GetDeclKind(Z3_func_decl decl) + { + Debug.Assert(decl != IntPtr.Zero); + + return (Z3_decl_kind)Native.Z3_get_decl_kind(nCtx, decl); + } + + /// + /// Get Sort for AST + /// + public Z3_sort GetSort(Z3_ast ast) + { + Debug.Assert(ast != IntPtr.Zero); + + return Native.Z3_get_sort(nCtx, ast); + } + + /// + /// Get the arguments for app + /// + /// + /// + public Z3_ast[] GetAppArgs(Z3_app app) + { + Debug.Assert(app != IntPtr.Zero); + + var numArgs = Native.Z3_get_app_num_args(nCtx, app); + var args = new Z3_ast[numArgs]; + for (uint i = 0; i < numArgs; i++) + { + args[i] = Native.Z3_get_app_arg(nCtx, app, i); + } + return args; + } + + /// + /// Get App Decl from IntPtr + /// + public Z3_func_decl GetAppDecl(Z3_ast ast) + { + Debug.Assert(ast != IntPtr.Zero); + + return Native.Z3_get_app_decl(nCtx, ast); + } + + /// + /// Get string name for Decl + /// + /// + /// + public string GetDeclName(Z3_func_decl decl) + { + Debug.Assert(decl != IntPtr.Zero); + + var namePtr = Native.Z3_get_decl_name(nCtx, decl); + return Marshal.PtrToStringAnsi(namePtr); + } + + /// + /// Get size of BitVector Sort + /// + public uint GetBvSortSize(Z3_sort bvSort) + { + Debug.Assert(bvSort != IntPtr.Zero); + + return Native.Z3_get_bv_sort_size(nCtx, bvSort); + } + + /// + /// Get the domain IntPtr for Sort + /// + public Z3_sort GetArraySortDomain(Z3_ast array) + { + Debug.Assert(array != IntPtr.Zero); + + return Native.Z3_get_array_sort_domain(nCtx, array); + } + + /// + /// Get the range IntPtr for Sort + /// + public Z3_sort GetArraySortRange(Z3_ast array) + { + Debug.Assert(array != IntPtr.Zero); + + return Native.Z3_get_array_sort_range(nCtx, array); + } + + /// + /// Try to get integer from AST + /// + /// + /// + /// + public bool TryGetNumeralInt(Z3_ast v, out int i) + { + Debug.Assert(v != IntPtr.Zero); + + int result = i = 0; + if (Native.Z3_get_numeral_int(nCtx, v, ref result) == 0) ; + { + return false; + } + i = result; + return true; + } + + /// + /// Try to get uint from AST + /// + /// + /// + /// + public bool TryGetNumeralUInt(Z3_ast v, out uint u) + { + Debug.Assert(v != IntPtr.Zero); + + uint result = u = 0; + if (Native.Z3_get_numeral_uint(nCtx, v, ref result) == 0) + { + return false; + } + u = result; + return true; + } + + /// + /// Try to get long from AST + /// + /// + /// + /// + /// + public bool TryGetNumeralInt64(Z3_ast v, out long i) + { + Debug.Assert(v != IntPtr.Zero); + + long result = i = 0; + if (Native.Z3_get_numeral_int64(nCtx, v, ref result) == 0) + { + return false; + } + i = result; + return true; + } + + /// + /// Try get ulong from AST + /// + /// + /// + /// + public bool TryGetNumeralUInt64(Z3_ast v, out ulong u) + { + Debug.Assert(v != IntPtr.Zero); + + ulong result = u = 0; + if (Native.Z3_get_numeral_uint64(nCtx, v, ref result) == 0) + { + return false; + } + u = result; + return true; + } + + /// + /// Get string for numeral ast + /// + /// + /// + public string GetNumeralString(Z3_ast v) + { + Debug.Assert(v != IntPtr.Zero); + return Native.Z3_get_numeral_string(nCtx, v); + } + + /// + /// Get printable string representing Z3_ast + /// + /// + /// + public string ToString(Z3_ast ast) + { + Debug.Assert(ast != IntPtr.Zero); + + return Native.Z3_ast_to_string(nCtx, ast); + } + + /// + /// Enable or disable warning messages + /// + /// + public void ToggleWarningMessages(bool turnOn) + => Native.Z3_toggle_warning_messages(turnOn ? (byte)1 : (byte)0); + + #endregion #region Internal + internal static Object creation_lock = new Object(); internal IntPtr m_ctx = IntPtr.Zero; internal Native.Z3_error_handler m_n_err_handler = null; internal IntPtr nCtx { get { return m_ctx; } } @@ -174,11 +1256,44 @@ namespace Microsoft.Z3 PrintMode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT; m_n_err_handler = new Native.Z3_error_handler(NativeErrorHandler); // keep reference so it doesn't get collected. Native.Z3_set_error_handler(m_ctx, m_n_err_handler); + GC.SuppressFinalize(this); } #endregion + #region Tracing + /// + /// Enable tracint to file + /// + /// + public void TraceToFile(string file) + { + Debug.Assert(!string.IsNullOrEmpty(file)); + Native.Z3_enable_trace(file); + } + + #endregion + + #region Dispose + + /// + /// Disposes of the context. + /// + public void Dispose() + { + if (m_ctx != IntPtr.Zero) + { + m_n_err_handler = null; + IntPtr ctx = m_ctx; + m_ctx = IntPtr.Zero; + Native.Z3_del_context(ctx); + } + else + GC.ReRegisterForFinalize(this); + } + #endregion + /// /// Utility to convert a vector object of ast to a .Net array @@ -194,7 +1309,6 @@ namespace Microsoft.Z3 result[i] = Native.Z3_ast_vector_get(nCtx, vec, i); Native.Z3_ast_vector_dec_ref(nCtx, vec); return result; - } /// @@ -205,7 +1319,7 @@ namespace Microsoft.Z3 public Statistics.Entry[] GetStatistics(Z3_stats stats) { Native.Z3_stats_inc_ref(nCtx, stats); - var result = Statistics.NativeEntries(nCtx, stats); + var result = Statistics.NativeEntries(nCtx, stats); Native.Z3_stats_dec_ref(nCtx, stats); return result; } diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index 417426b3b..dc2be0cc8 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -19,20 +19,11 @@ Notes: --*/ -using System; -using System.Diagnostics; -using System.Collections.Generic; - namespace Microsoft.Z3 { - using Z3_context = System.IntPtr; using Z3_ast = System.IntPtr; - using Z3_app = System.IntPtr; - using Z3_sort = System.IntPtr; using Z3_func_decl = System.IntPtr; - using Z3_model = System.IntPtr; - using Z3_func_interp = System.IntPtr; - using Z3_func_entry = System.IntPtr; + using Z3_sort = System.IntPtr; /// /// A Model contains interpretations (assignments) of constants and functions. @@ -67,7 +58,6 @@ namespace Microsoft.Z3 /// A FunctionInterpretation if the function has an interpretation in the model, null otherwise. public NativeFuncInterp FuncInterp(Z3_func_decl f) { - Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_range(Context.nCtx, f)); if (Native.Z3_get_arity(Context.nCtx, f) == 0) @@ -235,7 +225,6 @@ namespace Microsoft.Z3 /// public Z3_ast Evaluate(Z3_ast t, bool completion = false) => Eval(t, completion); - /// /// Evaluate expression to a double, assuming it is a numeral already. /// @@ -253,12 +242,16 @@ namespace Microsoft.Z3 /// /// One dimensional array of indices where the array is updated /// - public KeyValuePair[] Updates; + public KeyValuePair[] Updates; /// /// default Else case /// public Z3_ast Else; + + public Z3_sort[] Domain; + + public Z3_sort[] Range; } /// @@ -266,26 +259,34 @@ namespace Microsoft.Z3 /// /// /// null if the argument does evaluate to a sequence of stores to an array - public ArrayValue TryGetArrayValue(Z3_ast t) + public bool TryGetArrayValue(Z3_ast t, out ArrayValue result) { var r = Eval(t, true); // check that r is a sequence of store over a constant default array. var updates = new List>(); - var result = new ArrayValue(); - while (true) - { - // check that r is an app, and the decl-kind is Z3_OP_ARRAY_CONST or Z3_OP_ARRAY_STORE - // if it is Z3_OP_ARRAY_CONST then set result.Else and break; - // if it is ARRAY_STORE, then append to 'updates' and continue - // in other cases return null - return null; + //while (true) + //{ + // // check that r is an app, and the decl-kind is Z3_OP_ARRAY_CONST or Z3_OP_ARRAY_STORE + // // if it is Z3_OP_ARRAY_CONST then set result.Else and break; + // // if it is ARRAY_STORE, then append to 'updates' and continue + // // in other cases return null + // return false; + + //} + + if (updates.Any()) + { + result = new ArrayValue() + { + Updates = updates.ToArray() + }; + + return true; } -#if false - result.Updates = updates.ToArray(); - - return null; -#endif + + result = null; + return false; } /// diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs index 01e761e18..20d6a8e6f 100644 --- a/src/api/dotnet/NativeSolver.cs +++ b/src/api/dotnet/NativeSolver.cs @@ -18,24 +18,16 @@ Notes: --*/ -using System; -using System.Diagnostics; -using System.Linq; -using System.Collections.Generic; - namespace Microsoft.Z3 { - using Z3_context = System.IntPtr; using Z3_ast = System.IntPtr; - using Z3_app = System.IntPtr; - using Z3_sort = System.IntPtr; + using Z3_context = System.IntPtr; using Z3_func_decl = System.IntPtr; - using Z3_model = System.IntPtr; - using Z3_ast_vector = System.IntPtr; - using Z3_solver = System.IntPtr; - using Z3_symbol = System.IntPtr; using Z3_params = System.IntPtr; + using Z3_solver = System.IntPtr; + using Z3_sort = System.IntPtr; + using Z3_symbol = System.IntPtr; /// /// Solvers. @@ -45,21 +37,15 @@ namespace Microsoft.Z3 /// /// A string that describes all available solver parameters. /// - public string Help - { - get - { - return Native.Z3_solver_get_help(Context.nCtx, NativeObject); - } - } + public string Help => Native.Z3_solver_get_help(nCtx, z3solver); private void SetParam(Action setter) { - Z3_params p = Native.Z3_mk_params(Context.nCtx); - Native.Z3_params_inc_ref(Context.nCtx, p); + Z3_params p = Native.Z3_mk_params(nCtx); + Native.Z3_params_inc_ref(nCtx, p); setter(p); - Native.Z3_solver_set_params(Context.nCtx, NativeObject, p); - Native.Z3_params_dec_ref(Context.nCtx, p); + Native.Z3_solver_set_params(nCtx, z3solver, p); + Native.Z3_params_dec_ref(nCtx, p); } /// @@ -67,7 +53,7 @@ namespace Microsoft.Z3 /// public void Set(string name, bool value) { - SetParam((Z3_params p) => Native.Z3_params_set_bool(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), (byte)(value ? 1 : 0))); + SetParam((Z3_params p) => Native.Z3_params_set_bool(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), (byte)(value ? 1 : 0))); } /// @@ -75,7 +61,7 @@ namespace Microsoft.Z3 /// public void Set(string name, uint value) { - SetParam((Z3_params p) => Native.Z3_params_set_uint(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), value)); + SetParam((Z3_params p) => Native.Z3_params_set_uint(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value)); } /// @@ -83,7 +69,7 @@ namespace Microsoft.Z3 /// public void Set(string name, double value) { - SetParam((Z3_params p) => Native.Z3_params_set_double(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), value)); + SetParam((Z3_params p) => Native.Z3_params_set_double(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value)); } /// @@ -91,43 +77,43 @@ namespace Microsoft.Z3 /// public void Set(string name, string value) { - var value_sym = Native.Z3_mk_string_symbol(Context.nCtx, value); - SetParam((Z3_params p) => Native.Z3_params_set_symbol(Context.nCtx, p, Native.Z3_mk_string_symbol(Context.nCtx, name), value_sym)); + var value_sym = Native.Z3_mk_string_symbol(nCtx, value); + SetParam((Z3_params p) => Native.Z3_params_set_symbol(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value_sym)); } + #if false - /// - /// Sets parameter on the solver - /// - public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } /// /// Retrieves parameter descriptions for solver. /// public ParamDescrs ParameterDescriptions { - get { return new ParamDescrs(Context, Native.Z3_solver_get_param_descrs(Context.nCtx, NativeObject)); } + get { return new ParamDescrs(Context, Native.Z3_solver_get_param_descrs(nCtx, NativeObject)); } } - #endif /// @@ -135,38 +121,26 @@ namespace Microsoft.Z3 /// /// /// - public uint NumScopes - { - get { return Native.Z3_solver_get_num_scopes(Context.nCtx, NativeObject); } - } + public uint NumScopes => Native.Z3_solver_get_num_scopes(nCtx, z3solver); /// /// Creates a backtracking point. /// /// - public void Push() - { - Native.Z3_solver_push(Context.nCtx, NativeObject); - } + public void Push() => Native.Z3_solver_push(nCtx, z3solver); /// /// Backtracks backtracking points. /// /// Note that an exception is thrown if is not smaller than NumScopes /// - public void Pop(uint n = 1) - { - Native.Z3_solver_pop(Context.nCtx, NativeObject, n); - } + public void Pop(uint n = 1) => Native.Z3_solver_pop(nCtx, z3solver, n); /// /// Resets the Solver. /// /// This removes all assertions from the solver. - public void Reset() - { - Native.Z3_solver_reset(Context.nCtx, NativeObject); - } + public void Reset() => Native.Z3_solver_reset(nCtx, z3solver); /// /// Assert a constraint (or multiple) into the solver. @@ -178,25 +152,19 @@ namespace Microsoft.Z3 foreach (Z3_ast a in constraints) { - Native.Z3_solver_assert(Context.nCtx, NativeObject, a); + Native.Z3_solver_assert(nCtx, z3solver, a); } } /// /// Alias for Assert. /// - public void Add(params Z3_ast[] constraints) - { - Assert(constraints); - } + public void Add(params Z3_ast[] constraints) => Assert(constraints); /// /// Alias for Assert. /// - public void Add(IEnumerable constraints) - { - Assert(constraints.ToArray()); - } + public void Add(IEnumerable constraints) => Assert(constraints.ToArray()); /// /// Add constraints to ensure the function f can only be injective. @@ -209,28 +177,26 @@ namespace Microsoft.Z3 /// public void AssertInjective(Z3_func_decl f) { - uint arity = Native.Z3_get_arity(Context.nCtx, f); - Z3_sort range = Native.Z3_get_range(Context.nCtx, f); + uint arity = Native.Z3_get_arity(nCtx, f); + Z3_sort range = Native.Z3_get_range(nCtx, f); Z3_ast[] vars = new Z3_ast[arity]; Z3_sort[] sorts = new Z3_sort[arity]; Z3_symbol[] names = new Z3_symbol[arity]; for (uint i = 0; i < arity; ++i) { - Z3_sort domain = Native.Z3_get_domain(Context.nCtx, f, i); - //vars[i] = Context.MkBound(arity - i - 1, domain); + Z3_sort domain = Native.Z3_get_domain(nCtx, f, i); + vars[i] = ntvContext.MkBound(arity - i - 1, domain); sorts[i] = domain; - names[i] = Native.Z3_mk_int_symbol(Context.nCtx, (int)i); + names[i] = Native.Z3_mk_int_symbol(nCtx, (int)i); } Z3_ast app_f = IntPtr.Zero; // Context.MkApp(f, vars); for (uint i = 0; i < arity; ++i) { - Z3_sort domain = Native.Z3_get_domain(Context.nCtx, f, i); -#if false - Z3_func_decl proj = Native.Z3_mk_fresh_func_decl("inv", new Z3_sort[] { range }, domain); - Z3_ast body = Context.MkEq(vars[i], Context.MkApp(proj, app_f)); - Z3_ast q = Context.MkForall(names, sorts, body); + Z3_sort domain = Native.Z3_get_domain(nCtx, f, i); + Z3_func_decl proj = ntvContext.MkFreshFuncDecl("inv", new Z3_sort[] { range }, domain); + Z3_ast body = ntvContext.MkEq(vars[i], ntvContext.MkApp(proj, app_f)); + Z3_ast q = ntvContext.MkForall(names, sorts, body); Assert(q); -#endif } } @@ -254,7 +220,7 @@ namespace Microsoft.Z3 throw new Z3Exception("Argument size mismatch"); for (int i = 0; i < constraints.Length; i++) - Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraints[i], ps[i]); + Native.Z3_solver_assert_and_track(nCtx, z3solver, constraints[i], ps[i]); } /// @@ -273,57 +239,38 @@ namespace Microsoft.Z3 Debug.Assert(constraint != null); Debug.Assert(p != null); - Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraint, p); + Native.Z3_solver_assert_and_track(nCtx, z3solver, constraint, p); } /// /// Load solver assertions from a file. /// public void FromFile(string file) - { - Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); - } + => Native.Z3_solver_from_file(nCtx, z3solver, file); /// /// Load solver assertions from a string. /// public void FromString(string str) - { - Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); - } + => Native.Z3_solver_from_string(nCtx, z3solver, str); /// /// The number of assertions in the solver. /// public uint NumAssertions - { - get - { - return (uint)Context.ToArray(Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)).Length; - } - } + => (uint)ntvContext.ToArray(Native.Z3_solver_get_assertions(nCtx, z3solver)).Length; /// /// The set of asserted formulas. /// public Z3_ast[] Assertions - { - get - { - return Context.ToArray(Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); - } - } + => ntvContext.ToArray(Native.Z3_solver_get_assertions(nCtx, z3solver)); /// /// Currently inferred units. /// public Z3_ast[] Units - { - get - { - return Context.ToArray(Native.Z3_solver_get_units(Context.nCtx, NativeObject)); - } - } + => ntvContext.ToArray(Native.Z3_solver_get_units(nCtx, z3solver)); /// /// Checks whether the assertions in the solver are consistent or not. @@ -337,9 +284,9 @@ namespace Microsoft.Z3 { Z3_lbool r; if (assumptions == null || assumptions.Length == 0) - r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); + r = (Z3_lbool)Native.Z3_solver_check(nCtx, z3solver); else - r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)assumptions.Length, assumptions); + r = (Z3_lbool)Native.Z3_solver_check_assumptions(nCtx, z3solver, (uint)assumptions.Length, assumptions); return lboolToStatus(r); } @@ -356,13 +303,12 @@ namespace Microsoft.Z3 Z3_lbool r; Z3_ast[] asms = assumptions.ToArray(); if (asms.Length == 0) - r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); + r = (Z3_lbool)Native.Z3_solver_check(nCtx, z3solver); else - r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)asms.Length, asms); + r = (Z3_lbool)Native.Z3_solver_check_assumptions(nCtx, z3solver, (uint)asms.Length, asms); return lboolToStatus(r); } - /// /// The model of the last Check(params Expr[] assumptions). /// @@ -374,11 +320,10 @@ namespace Microsoft.Z3 { get { - IntPtr x = Native.Z3_solver_get_model(Context.nCtx, NativeObject); - if (x == IntPtr.Zero) - return null; - else - return new NativeModel(Context, x); + IntPtr x = Native.Z3_solver_get_model(nCtx, z3solver); + return x == IntPtr.Zero + ? null + : new NativeModel(ntvContext, x); } } @@ -390,12 +335,7 @@ namespace Microsoft.Z3 /// if its results was not UNSATISFIABLE, or if proof production is disabled. /// public Z3_ast Proof - { - get - { - return Native.Z3_solver_get_proof(Context.nCtx, NativeObject); - } - } + => Native.Z3_solver_get_proof(nCtx, z3solver); /// /// The unsat core of the last Check. @@ -406,23 +346,13 @@ namespace Microsoft.Z3 /// if its results was not UNSATISFIABLE, or if core production is disabled. /// public Z3_ast[] UnsatCore - { - get - { - return Context.ToArray(Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); - } - } + => ntvContext.ToArray(Native.Z3_solver_get_unsat_core(nCtx, z3solver)); /// /// A brief justification of why the last call to Check returned UNKNOWN. /// public string ReasonUnknown - { - get - { - return Native.Z3_solver_get_reason_unknown(Context.nCtx, NativeObject); - } - } + => Native.Z3_solver_get_reason_unknown(nCtx, z3solver); /// /// Create a clone of the current solver with respect to ctx. @@ -430,7 +360,7 @@ namespace Microsoft.Z3 public NativeSolver Translate(NativeContext ctx) { Debug.Assert(ctx != null); - return new NativeSolver(ctx, Native.Z3_solver_translate(Context.nCtx, NativeObject, ctx.nCtx)); + return new NativeSolver(ctx, Native.Z3_solver_translate(nCtx, z3solver, ctx.nCtx)); } /// @@ -438,9 +368,10 @@ namespace Microsoft.Z3 /// public void ImportModelConverter(NativeSolver src) { - Native.Z3_solver_import_model_converter(Context.nCtx, src.NativeObject, NativeObject); - } + Debug.Assert(src != null); + Native.Z3_solver_import_model_converter(nCtx, src.z3solver, z3solver); + } /// /// Solver statistics. @@ -449,8 +380,8 @@ namespace Microsoft.Z3 { get { - var stats = Native.Z3_solver_get_statistics(Context.nCtx, NativeObject); - return Context.GetStatistics(stats); + var stats = Native.Z3_solver_get_statistics(nCtx, z3solver); + return ntvContext.GetStatistics(stats); } } @@ -459,19 +390,23 @@ namespace Microsoft.Z3 /// public override string ToString() { - return Native.Z3_solver_to_string(Context.nCtx, NativeObject); + return Native.Z3_solver_to_string(nCtx, z3solver); } #region Internal - NativeContext Context; - IntPtr NativeObject; - internal NativeSolver(NativeContext ctx, Z3_solver obj) - { - Context = ctx; - NativeObject = obj; + readonly NativeContext ntvContext; + Z3_solver z3solver; + Z3_context nCtx => ntvContext.nCtx; - Debug.Assert(ctx != null); - Native.Z3_solver_inc_ref(ctx.nCtx, obj); + internal NativeSolver(NativeContext nativeCtx, Z3_solver z3solver) + { + Debug.Assert(nCtx != IntPtr.Zero); + Debug.Assert(z3solver != IntPtr.Zero); + + this.ntvContext = nativeCtx; + this.z3solver = z3solver; + + Native.Z3_solver_inc_ref(nCtx, z3solver); } /// @@ -487,10 +422,10 @@ namespace Microsoft.Z3 /// public void Dispose() { - if (NativeObject != IntPtr.Zero) + if (z3solver != IntPtr.Zero) { - Native.Z3_solver_dec_ref(Context.nCtx, NativeObject); - NativeObject = IntPtr.Zero; + Native.Z3_solver_dec_ref(nCtx, z3solver); + z3solver = IntPtr.Zero; } GC.SuppressFinalize(this); } From 35fb95648b0aa7ba2304a5141ebe607c1122bd07 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Thu, 3 Mar 2022 19:42:06 +0100 Subject: [PATCH 092/258] Updated user-propagator example (#5879) --- examples/userPropagator/CMakeLists.txt | 10 +- examples/userPropagator/common.h | 77 +++ examples/userPropagator/example.cpp | 492 +++++++++--------- examples/userPropagator/example.pdf | Bin 286105 -> 341835 bytes examples/userPropagator/user_propagator.h | 87 ++++ .../user_propagator_created_maximisation.h | 338 ++++++++++++ .../user_propagator_internal_maximisation.h | 30 ++ .../user_propagator_subquery_maximisation.h | 51 ++ .../user_propagator_with_theory.h | 50 ++ 9 files changed, 893 insertions(+), 242 deletions(-) create mode 100644 examples/userPropagator/common.h create mode 100644 examples/userPropagator/user_propagator.h create mode 100644 examples/userPropagator/user_propagator_created_maximisation.h create mode 100644 examples/userPropagator/user_propagator_internal_maximisation.h create mode 100644 examples/userPropagator/user_propagator_subquery_maximisation.h create mode 100644 examples/userPropagator/user_propagator_with_theory.h diff --git a/examples/userPropagator/CMakeLists.txt b/examples/userPropagator/CMakeLists.txt index 9ed916d46..384d257dc 100644 --- a/examples/userPropagator/CMakeLists.txt +++ b/examples/userPropagator/CMakeLists.txt @@ -24,7 +24,15 @@ message(STATUS "Z3_FOUND: ${Z3_FOUND}") message(STATUS "Found Z3 ${Z3_VERSION_STRING}") message(STATUS "Z3_DIR: ${Z3_DIR}") -add_executable(user_propagator_example example.cpp) +add_executable(user_propagator_example + example.cpp + common.h + user_propagator.h + user_propagator_with_theory.h + user_propagator_subquery_maximisation.h + user_propagator_internal_maximisation.h + user_propagator_created_maximisation.h) + target_include_directories(user_propagator_example PRIVATE ${Z3_CXX_INCLUDE_DIRS}) target_link_libraries(user_propagator_example PRIVATE ${Z3_LIBRARIES}) diff --git a/examples/userPropagator/common.h b/examples/userPropagator/common.h new file mode 100644 index 000000000..3c9f3b299 --- /dev/null +++ b/examples/userPropagator/common.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "z3++.h" + +using std::to_string; + +#define SIZE(x) std::extent::value + +// #define VERBOSE // Log events +#ifdef VERBOSE +#define WriteEmptyLine std::cout << std::endl +#define WriteLine(x) std::cout << (x) << std::endl +#define Write(x) std::cout << x +#else +#define WriteEmptyLine +#define WriteLine(x) +#define Write(x) +#endif + +int log2i(unsigned n) { + if (n <= 0) { + return 0; + } + if (n <= 2) { + return 1; + } + unsigned l = 1; + int i = 0; + while (l < n) { + l <<= 1; + i++; + } + return i; +} + +typedef std::vector simple_model; + +// For putting z3 expressions in hash-tables +namespace std { + + template<> + struct hash { + std::size_t operator()(const simple_model &m) const { + size_t hash = 0; + for (unsigned i = 0; i < m.size(); i++) { + hash *= m.size(); + hash += m[i]; + } + return hash; + } + }; + + template<> + struct hash { + std::size_t operator()(const z3::expr &k) const { + return k.hash(); + } + }; + + // Do not use Z3's == operator in the hash table + template<> + struct equal_to { + bool operator()(const z3::expr &lhs, const z3::expr &rhs) const { + return z3::eq(lhs, rhs); + } + }; +} \ No newline at end of file diff --git a/examples/userPropagator/example.cpp b/examples/userPropagator/example.cpp index 1b6888798..9c3e7cf3e 100644 --- a/examples/userPropagator/example.cpp +++ b/examples/userPropagator/example.cpp @@ -1,13 +1,8 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "z3++.h" +#include "user_propagator.h" +#include "user_propagator_with_theory.h" +#include "user_propagator_subquery_maximisation.h" +#include "user_propagator_internal_maximisation.h" +#include "user_propagator_created_maximisation.h" /** * The program solves the n-queens problem (number of solutions) with 4 different approaches @@ -20,238 +15,57 @@ */ using namespace std::chrono; -using std::to_string; -#define QUEEN #define REPETITIONS 5 -#define SIZE(x) std::extent::value +#define MIN_BOARD 4 +#define MAX_BOARD1 12 +#define MAX_BOARD2 12 -#ifdef LOG -#define WriteEmptyLine std::cout << std::endl -#define WriteLine(x) std::cout << (x) << std::endl -#define Write(x) std::cout << x -#else -#define WriteEmptyLine -#define WriteLine(x) -#define Write(x) -#endif - -typedef std::vector model; - -struct model_hash_function { - std::size_t operator()(const model &m) const { - size_t hash = 0; - for (unsigned i = 0; i < m.size(); i++) { - hash *= m.size(); - hash += m[i]; - } - return hash; - } -}; - -namespace std { - - template<> - struct hash { - std::size_t operator()(const z3::expr &k) const { - return k.hash(); - } - }; -} - -// Do not use Z3's == operator in the hash table -namespace std { - - template<> - struct equal_to { - bool operator()(const z3::expr &lhs, const z3::expr &rhs) const { - return z3::eq(lhs, rhs); - } - }; -} - -class user_propagator : public z3::user_propagator_base { - -protected: - - unsigned board; - std::unordered_map& id_mapping; - model currentModel; - std::unordered_set modelSet; - std::vector fixedValues; - std::stack fixedCnt; - - int solutionId = 1; - -public: - - int getModelCount() const { - return solutionId - 1; - } - - void final() final { - z3::expr_vector conflicting(fixedValues[0].ctx()); - for (auto&& v : fixedValues) - conflicting.push_back(v); - this->conflict(conflicting); - if (modelSet.find(currentModel) != modelSet.end()) { - WriteLine("Got already computed model"); - return; - } - Write("Model #" << solutionId << ":\n"); - solutionId++; -#ifdef LOG - for (unsigned i = 0; i < fixedValues.size(); i++) { - unsigned id = fixedValues[i]; - WriteLine("q" + to_string(id_mapping[id]) + " = " + to_string(currentModel[id])); - } -#endif - modelSet.insert(currentModel); - WriteEmptyLine; - } - - static unsigned bvToInt(z3::expr e) { - return (unsigned)e.get_numeral_int(); - } - - void fixed(z3::expr const &ast, z3::expr const &value) override { - fixedValues.push_back(ast); - unsigned valueBv = bvToInt(value); - currentModel[id_mapping[ast]] = valueBv; - } - - user_propagator(z3::solver *s, std::unordered_map& idMapping, unsigned board) - : user_propagator_base(s), board(board), id_mapping(idMapping), currentModel(board, (unsigned)-1) { - - this->register_fixed(); - this->register_final(); - } - - ~user_propagator() = default; - - void push() override { - fixedCnt.push((unsigned) fixedValues.size()); - } - - void pop(unsigned num_scopes) override { - for (unsigned i = 0; i < num_scopes; i++) { - unsigned lastCnt = fixedCnt.top(); - fixedCnt.pop(); - for (auto j = fixedValues.size(); j > lastCnt; j--) { - currentModel[fixedValues[j - 1]] = (unsigned)-1; - } - fixedValues.erase(fixedValues.cbegin() + lastCnt, fixedValues.cend()); - } - } - - user_propagator_base *fresh(Z3_context) override { - return this; - } -}; - -class user_propagator_with_theory : public user_propagator { - -public: - - void fixed(z3::expr const &ast, z3::expr const &value) override { - unsigned queenId = id_mapping[ast]; - unsigned queenPos = bvToInt(value); - - if (queenPos >= board) { - z3::expr_vector conflicting(ast.ctx()); - conflicting.push_back(ast); - this->conflict(conflicting); - return; - } - - for (z3::expr fixed : fixedValues) { - unsigned otherId = id_mapping[fixed]; - unsigned otherPos = currentModel[fixed]; - - if (queenPos == otherPos) { - z3::expr_vector conflicting(ast.ctx()); - conflicting.push_back(ast); - conflicting.push_back(fixed); - this->conflict(conflicting); - continue; - } -#ifdef QUEEN - int diffY = abs((int)queenId - (int)otherId); - int diffX = abs((int)queenPos - (int)otherPos); - if (diffX == diffY) { - z3::expr_vector conflicting(ast.ctx()); - conflicting.push_back(ast); - conflicting.push_back(fixed); - this->conflict(conflicting); - } -#endif - } - - fixedValues.push_back(ast); - currentModel[id_mapping[ast]] = queenPos; - } - - user_propagator_with_theory(z3::solver *s, std::unordered_map& idMapping, unsigned board) - : user_propagator(s, idMapping, board) {} -}; - -int log2i(unsigned n) { - if (n <= 0) { - return 0; - } - if (n <= 2) { - return 1; - } - unsigned l = 1; - int i = 0; - while (l < n) { - l <<= 1; - i++; - } - return i; -} - -std::vector createQueens(z3::context &context, unsigned num) { - std::vector queens; - int bits = log2i(num) + 1 /*to detect potential overflow in the diagonal*/; +z3::expr_vector createQueens(z3::context &context, unsigned num, int bits, std::string prefix) { + z3::expr_vector queens(context); for (unsigned i = 0; i < num; i++) { - queens.push_back(context.bv_const((std::string("q") + to_string(i)).c_str(), bits)); + queens.push_back(context.bv_const((prefix + "q" + to_string(i)).c_str(), bits)); } return queens; } -void createConstraints(z3::context &context, z3::solver &solver, const std::vector &queens) { +z3::expr_vector createQueens(z3::context &context, unsigned num) { + return createQueens(context, num, log2i(num) + 1, ""); +} + +z3::expr createConstraints(z3::context &context, const z3::expr_vector &queens) { + z3::expr_vector assertions(context); for (unsigned i = 0; i < queens.size(); i++) { // assert column range - solver.add(z3::uge(queens[i], 0)); - solver.add(z3::ule(queens[i], (int) (queens.size() - 1))); + assertions.push_back(z3::uge(queens[i], 0)); + assertions.push_back(z3::ule(queens[i], (int) (queens.size() - 1))); } z3::expr_vector distinct(context); - for (const z3::expr &queen : queens) { + for (const z3::expr &queen: queens) { distinct.push_back(queen); } - solver.add(z3::distinct(distinct)); + assertions.push_back(z3::distinct(distinct)); -#ifdef QUEEN for (unsigned i = 0; i < queens.size(); i++) { for (unsigned j = i + 1; j < queens.size(); j++) { - solver.add((int)(j - i) != (queens[j] - queens[i])); - solver.add((int)(j - i) != (queens[i] - queens[j])); + assertions.push_back((int) (j - i) != (queens[j] - queens[i])); + assertions.push_back((int) (j - i) != (queens[i] - queens[j])); } } -#endif + + return z3::mk_and(assertions); } int test01(unsigned num, bool simple) { z3::context context; z3::solver solver(context, !simple ? Z3_mk_solver(context) : Z3_mk_simple_solver(context)); - std::vector queens = createQueens(context, num); + z3::expr_vector queens = createQueens(context, num); - createConstraints(context, solver, queens); + solver.add(createConstraints(context, queens)); int solutionId = 1; @@ -292,7 +106,7 @@ inline int test1(unsigned num) { int test23(unsigned num, bool withTheory) { z3::context context; - z3::solver solver(context, Z3_mk_simple_solver(context)); + z3::solver solver(context, z3::solver::simple()); std::unordered_map idMapping; user_propagator *propagator; @@ -303,7 +117,7 @@ int test23(unsigned num, bool withTheory) { propagator = new user_propagator_with_theory(&solver, idMapping, num); } - std::vector queens = createQueens(context, num); + z3::expr_vector queens = createQueens(context, num); for (unsigned i = 0; i < queens.size(); i++) { propagator->add(queens[i]); @@ -311,7 +125,7 @@ int test23(unsigned num, bool withTheory) { } if (!withTheory) { - createConstraints(context, solver, queens); + solver.add(createConstraints(context, queens)); } solver.check(); @@ -328,50 +142,246 @@ inline int test3(unsigned num) { return test23(num, true); } +int test4(unsigned num) { + z3::context context; + z3::solver solver(context, z3::solver::simple()); + + z3::expr_vector queens1 = createQueens(context, num, log2i(num * num), ""); // square to avoid overflow during summation + + z3::expr valid1 = createConstraints(context, queens1); + + z3::expr_vector queens2 = createQueens(context, num, log2i(num * num), "forall_"); + + z3::expr valid2 = createConstraints(context, queens2); + + z3::expr manhattanSum1 = context.bv_val(0, queens1[0].get_sort().bv_size()); + z3::expr manhattanSum2 = context.bv_val(0, queens2[0].get_sort().bv_size()); + + for (int i = 1; i < queens1.size(); i++) { + manhattanSum1 = manhattanSum1 + z3::ite(z3::uge(queens1[i], queens1[i - 1]), queens1[i] - queens1[i - 1], queens1[i - 1] - queens1[i]); + manhattanSum2 = manhattanSum2 + z3::ite(z3::uge(queens2[i], queens2[i - 1]), queens2[i] - queens2[i - 1], queens2[i - 1] - queens2[i]); + } + + + solver.add(valid1 && z3::forall(queens2, z3::implies(valid2, manhattanSum1 >= manhattanSum2))); + + solver.check(); + z3::model model = solver.get_model(); + + int max = 0; + + int prev, curr; + curr = model.eval(queens1[0]).get_numeral_int(); + + for (unsigned i = 1; i < num; i++) { + prev = curr; + curr = model.eval(queens1[i]).get_numeral_int(); + max += abs(curr - prev); + } + + return max; +} + +int test5(unsigned num) { + z3::context context; + z3::solver solver(context, z3::solver::simple()); + std::unordered_map idMapping; + + z3::expr_vector queens = createQueens(context, num, log2i(num * num), ""); + + solver.add(createConstraints(context, queens)); + + user_propagator_subquery_maximisation propagator(&solver, idMapping, num, queens); + + for (unsigned i = 0; i < queens.size(); i++) { + propagator.add(queens[i]); + idMapping[queens[i]] = i; + } + + solver.check(); + z3::model model = solver.get_model(); + + int max = 0; + + int prev, curr; + curr = model.eval(queens[0]).get_numeral_int(); + for (unsigned i = 1; i < num; i++) { + prev = curr; + curr = model.eval(queens[i]).get_numeral_int(); + max += abs(curr - prev); + } + + return max; +} + +int test6(unsigned num) { + z3::context context; + z3::solver solver(context, z3::solver::simple()); + std::unordered_map idMapping; + + z3::expr_vector queens = createQueens(context, num, log2i(num * num), ""); + + solver.add(createConstraints(context, queens)); + + user_propagator_internal_maximisation propagator(&solver, idMapping, num, queens); + + for (unsigned i = 0; i < queens.size(); i++) { + propagator.add(queens[i]); + idMapping[queens[i]] = i; + } + + solver.check(); + return propagator.best; +} + +int test7(unsigned num) { + z3::context context; + z3::solver solver(context, z3::solver::simple()); + + z3::expr_vector queens1 = createQueens(context, num, log2i(num * num), ""); + z3::expr_vector queens2 = createQueens(context, num, log2i(num * num), "forall_"); + + z3::expr manhattanSum1 = context.bv_val(0, queens1[0].get_sort().bv_size()); + z3::expr manhattanSum2 = context.bv_val(0, queens2[0].get_sort().bv_size()); + + for (int i = 1; i < queens1.size(); i++) { + manhattanSum1 = manhattanSum1 + z3::ite(z3::uge(queens1[i], queens1[i - 1]), queens1[i] - queens1[i - 1], queens1[i - 1] - queens1[i]); + manhattanSum2 = manhattanSum2 + z3::ite(z3::uge(queens2[i], queens2[i - 1]), queens2[i] - queens2[i - 1], queens2[i - 1] - queens2[i]); + } + + z3::sort_vector domain(context); + for (int i = 0; i < queens1.size(); i++) { + domain.push_back(queens1[i].get_sort()); + } + z3::func_decl validFunc = context.user_propagate_function(context.str_symbol("valid"), domain, context.bool_sort()); + + solver.add(validFunc(queens1) && z3::forall(queens2, z3::implies(validFunc(queens2), manhattanSum1 >= manhattanSum2))); + user_propagator_created_maximisation propagator(&solver, num); + + solver.check(); + z3::model model = solver.get_model(); + + int max = 0; + + int prev, curr; + curr = model.eval(queens1[0]).get_numeral_int(); + + for (unsigned i = 1; i < num; i++) { + prev = curr; + curr = model.eval(queens1[i]).get_numeral_int(); + max += abs(curr - prev); + } + + return max; +} + int main() { - for (int num = 4; num <= 11; num++) { + for (int num = MIN_BOARD; num <= MAX_BOARD1; num++) { + + std::cout << "num = " << num << ":\n" << std::endl; + + unsigned seed = (unsigned) high_resolution_clock::now().time_since_epoch().count(); + const char *testName[] = + { + "BV + Blocking clauses (Default solver)", + "BV + Blocking clauses (Simple solver)", + "BV + Adding conflicts", + "Custom theory + conflicts", + }; + int permutation[4] = {0, 1, 2, 3,}; + double timeResults[REPETITIONS * SIZE(permutation)]; + + for (int rep = 0; rep < REPETITIONS; rep++) { + // Execute strategies in a randomised order + std::shuffle(&permutation[0], &permutation[SIZE(permutation) - 1], std::default_random_engine(seed)); + + for (int i : permutation) { + int modelCount = -1; + + auto now1 = high_resolution_clock::now(); + + switch (i) { + case 0: + modelCount = test0(num); + break; + case 1: + modelCount = test1(num); + break; + case 2: + modelCount = test2(num); + break; + case 3: + modelCount = test3(num); + break; + default: + WriteLine("Unknown case"); + break; + } + auto now2 = high_resolution_clock::now(); + duration ms = now2 - now1; + std::cout << testName[i] << " took " << ms.count() << "ms (" << modelCount << " models)" << std::endl; + timeResults[rep * SIZE(permutation) + i] = ms.count(); + WriteLine("-------------"); + } + } + + std::cout << "\n" << std::endl; + + for (unsigned i = 0; i < SIZE(permutation); i++) { + std::cout << testName[i]; + double sum = 0; + for (int j = 0; j < REPETITIONS; j++) { + std::cout << " " << timeResults[j * SIZE(permutation) + i] << "ms"; + sum += timeResults[j * SIZE(permutation) + i]; + } + std::cout << " | avg: " << sum / REPETITIONS << "ms" << std::endl; + } + + std::cout << std::endl; + } + + z3::set_param("smt.ematching", "false"); + z3::set_param("smt.mbqi", "true"); + + std::cout << "\nMaximal distance:" << std::endl; + + for (int num = MIN_BOARD; num <= MAX_BOARD2; num++) { std::cout << "num = " << num << ":\n" << std::endl; unsigned seed = (unsigned) high_resolution_clock::now().time_since_epoch().count(); const char *testName[] = { - "BV + Blocking clauses (Default solver)", - "BV + Blocking clauses (Simple solver)", - "BV + Adding conflicts", - "Custom theory + conflicts", - }; - int permutation[4] = - { - 0, - 1, - 2, - 3, + "Ordinary/Direct Encoding", + "SubQuery in final", + "Assert Smaller in final", + "created", }; + int permutation[4] = {0, 1, 2, 3,}; double timeResults[REPETITIONS * SIZE(permutation)]; for (int rep = 0; rep < REPETITIONS; rep++) { // Execute strategies in a randomised order std::shuffle(&permutation[0], &permutation[SIZE(permutation) - 1], std::default_random_engine(seed)); - for (int i : permutation) { - int modelCount = -1; + for (int i: permutation) { + int max = -1; auto now1 = high_resolution_clock::now(); - switch (i) { - case 0: - modelCount = test0(num); + switch (i + 4) { + case 4: + max = test4(num); break; - case 1: - modelCount = test1(num); + case 5: + max = test5(num); break; - case 2: - modelCount = test2(num); + case 6: + max = test6(num); break; - case 3: - modelCount = test3(num); + case 7: + max = test7(num); break; default: WriteLine("Unknown case"); @@ -379,7 +389,7 @@ int main() { } auto now2 = high_resolution_clock::now(); duration ms = now2 - now1; - std::cout << testName[i] << " took " << ms.count() << "ms (" << modelCount << " models)" << std::endl; + std::cout << testName[i] << " took " << ms.count() << "ms. Max: " << max << std::endl; timeResults[rep * SIZE(permutation) + i] = ms.count(); WriteLine("-------------"); } @@ -399,4 +409,4 @@ int main() { std::cout << std::endl; } -} +} \ No newline at end of file diff --git a/examples/userPropagator/example.pdf b/examples/userPropagator/example.pdf index 2e802259cd2e80e0d78195f53c791cdc5936f3f5..eaf3c9952106dec2cfb0438e02c266a710936047 100644 GIT binary patch delta 181377 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
uWw|wh{@d@ z{X8-BldMseu}{)O%$^fM%iJ-k72D{5vTEcucqANd^ar(YcR5oS#PG|{JKaEy^rUB& z*`ayIx8GP*ZQM7qdEdkz;;Nn6FZx$o5K1W-!PjfaUr+=v$>^n-tuNDv{``OLMLtKz zrHLTS75YSv+b$A|MTS|p8W_bWE?Pz!kRbqZV0m$g`AfVpV_bCvG?0|I;4PvokW8Gd zf=oc@kXy#vHsCYZ6`W0i0qBC(Jeaq-<-u5pDtx*?Vl#Q07~C?xOFtGz&h&?qS4 zB*C&wQg}>==5UO771`LJ6mfsn`%oytKsz}=Gb+)UqNOVHyK;x)Fh;|7yKv_rc=6VQ zYQArWR@1Ae1KE9T^rqBV=?NiU64azq@QK7|d!3j7!89(5V)kw3JEf00h>E!MuY}GZ zuG?3==tY>z)cQH$X~Cd|XZG>oQ5>v}+d;`wN42v|MnTNM+S>7sPr-jqjmbhA`m0+- zzY2@<>C76mMc>?7+Idnva@@ETk(xqNXbL|=D5^S9GM1^^k(_!$q6CgpOtkHxZq=N= z=Q$b+8VJ^5k?j~obgHS*(k(|d&$+6=9wFPx#K_P>1JNyGY%DS88{hEA?zaz?q!in> z;n5-KX?knp++xWc_7;EQT(c8Wt1ll)@p<9v(=D8*ps&E%q7S{_Q#jtG>_wWI4gtvd zSymb9yzq^{^dU4)OsiXV`IeYZY}S52G%8{9tq(93>{xDR&y!&|ejn(OPGIz<9{u#& z`5KY#Lq(MFmybQdq*TSvT3(jnf*|@&eygXMIPPz$c(aM0LR){<4)pqs7i3VlYnN?@ z(V=TgZa?0o{V<;Xc*{aZY1pe!yhoc0HDP6iQN!V>>?P|uoirI=fn&STw_Zuf_+xz; zPQ9HA4lY$mP-CT3W?}&YpTV1mPEJ#D8=BO#3Gvhq>J=mXtyb=lV0NogyO!L-Y05<@ zbJQZFAn(z46tjO~!N!k%G3zbcYzoLiCf-9myhMB0?a)=*V;%suK(%i$uIGcn%?MpS zW55nph2~F7ND_kV0~tmSa+e!egRPYQ?D$Bp>(d5)WiPX=FeVAkv%K|J3#7;Bg6JSTnG>Uq-;0yju;YZReaI$12c zC#rB&r53;_H*DZojS`oh1toQV(bVyVKRxXanMCa5O=e9I4|57|O--_8fh(n?b7Bj2!I)nG~j6;-Y9!PKvCmF$1L`b zdvkvZ2al^v!{Y)DI1xm(c%NOb9S1F@D=OZxjGt8-78$2~Fh-vLVb&S(-Jlcpb%PZv z*l|?DIym?%fe`-JQ3{=MahoHYqN$kjv<%oe9*Oo$`a=4daE^S0KN z^KPzBhw!GhqBxmbs?}OLiYD)X)p&3N4DWwlUrh5)o&H__CQ5W^ui!(4fo^jY`Uu{hbI3J25R&QN7hXQD1rox{Bo7I$rCw)2+ zha-NjUpb8JDtdlzY(~A9^WfUzmX#gJ-qoOgvccO=?8SUdf*=2CHb^qRJiP`XXvb5P zFH+i(Ay9AiNfwKQjJ9siiGH!d2k(D`nZJ)WBIDayl{D%+%j^6h;E-S0-NvE9=CUS_ zF8@Jsk4Du?UCTryU~#AC3+f1uW3H9=(ZXmOG9u>j2eeNvIP6g>Sy=o2@8LZ+xTSE zzRbvOgTfdH-FV^6ZHFr5le4?TZ4YJkZ0hCxgtt;%NR7id8`MITMNCLQA5zmZG2Q#? zgwHA^3Z6#fVx|+)EW^F$&?|E4PjYLSNnnrTv%X8?qh`p zUFF{?66FV5a;7eLb{+>a6SIE@%Q~MrgL5^aT^~0ztOr^mdE) z<#fhZ_Jao~a92&FpDt?%e{E|Se&ubPj@VRTT*W=#KNRFrjOm)IwyhUh-lgBB>LmZ% z(mO1`Sd+#Z&RD|uD7G<#wF^|V=+3HjY7hE(l4oJk-2fNB9_f8ne$RhWVk<9!zjtdO zD@&x){AyMS+h#o`Dwe_PIXX(uf-84iCw|vV5Y#s`Wy;a<){XKP#w&(58Vaz0vJ9|K zY*#Cl;ct_SqnW#^OQQXNrSlfjOK6g?T@4R$p04qibo?5TeMY@Top{}biR*33iGc*roi+gD;l0h+#Rq@iV;If;6%Tg?6< zB$QE-L3OF6J`(tn@WIa$hsWcg1$sgEsklqLB?H4XS0&UKMA5Bo>^n^4p&DLpHA7fq z7>)tlqAF|OXx#7~(oqJQB`(|=9Mk(xNXw`(fPnXHhi_mvZpMH7TDh>{Xx}TF;>5yy zr$e5-F=j&k8SI~)^wF_qF`0+69TmoQEx(hvwNd%{2}vHgA`tlC>Lp(UQ@yVRzW?!pv~@!r%J_p-CPJUa%a3C_grY6wC5VgZ3!WQsFB8#ZnAP#1tRzM4=JtZ zO>vY{(i!e({gdnn@A*J7J*^8Hgjj=h=ecx4op|>ki_2aQ;d+dXq4MYRsSEE9$T9o8 z_tmCMA^3Q3B%bje_#EB2odiopZYch4?y9YPrS*LT0;qo&C7$xBFXTb6zo_%=Q*<%= z`vnjXei&12&<4fBV_-*hvFl=X zu-2=YeCsN)6{BmC36B5;&bei8_<4VZR1{aIGWk3l!KODPHF$dn3OD9P zgsT+U|=NfXST$% zf@FVbyPQBU0V)XutL~yiE&UlFYTR63$0>)1eyVN-{$=&l!Cr)n{un*7#!@M<27+@T z4=Fu$HFl3LoPAm(w|#`@c)tCj)rn%su>i(0jWzb-vg_bNi_+jLPyxGY{7L#A#i$Kr zh86h{y@I#l+&KTWnu`-(ObZ=RQPn?$S#N*Ltw*VWiKLIFC83p=Gx$vAlwYUVDb|*0 z%ndIHaU~ROqzV}_ynu7yd5U&LPays+kE|NjZBw7qmx{T7=v>Xgm5*A;7GrlR9d(&+ zpy(+Y63`l2?{=Fn1*EFFdFrkx`R0@?L~bIJURT3Oks|Uw!Ahp-%qYT`$O`D_XQh9_ z*G)}zC{>ZYs9-`Len1@>EyCMmJKlWYhE)KO&-emNWFp@>J|zLa$?^6=hY)o5O}|H! zP2^4T-k#~w$*#$(lFl}&M@iwh>?aD5BOh?rvc0geM09B@Fnx9_a>=q<^h_Z%-^IUY z_X`;3NyH!4vucu1Bk%V+gh(QOhn#;8pom!d@cda4117~|u_YI$WODTx_4&3$;?UXf z>yKaE`O85lpTFc-Z*=Caa%Q#O)a!-NQ%rG5rg8sNQ2%_aRt;r-Z{K`?C}D~=m4)SbrWL$an}}KNbAF#HWYjmW!?@rxG;=t*oD|1=pN8pR=E|D1Ajz(LrjIMV^y04ENpA(*%d<*@-= z2+knZo|m_FuQ7IB*-}3ulHY&K5l?6lFmTl3H#(;2Yxj=pq^}!GC{U3&Tw_r?>FH^1XYc_MOc|kygW3gVB4W>F<>2JvP%gltcfl13s$SgSKa78@oub%a`5&?c z5+>)1oDPbUr6$U3kIWMLh!59el;9<2@VD_6yhyH+3vjQS*fJaNIbJ;)3S6rgseETu zw29fsUC=bn>)10ugJtPTB{5C}tn!_qTh&~4`J7XS7F-RS4E zx#f=7)TZn$l2>!5PgR6&;Z^}yx!Vmwk_ybVgCzYPf)J-MGawD%s;re3CjN_w8q>nCn6x z{8NbdFIIB}%V($(mE)+^v>zY*a3j;?8FYhg6?+VJIJbWtDlR-3yxG1m?R_fb(&ff7 zQ}*b--QMIVa*EUnwD&TY|Cyo8go#%h_STBT!6a-#lCS!F9D9<}LZ}}ZDK-Fw%ttPX zeDJeEB#C3y<|ySOG8yuYfW3=?<7)~6 zN#6H(FL!_4-u3e@qB~qBRiNtr8nD6r5*sW7EcU6qfGa4DUY+@LoHl=?H`NZf}xyF9eXw2wt`&d5lndw9J za7?DE!u91zw8ax|vOKI=KglK9?GA)(DAYS7l1-v3W5|F}rmDR_RCI1i!E1vY&Q}s7 z{1~Gk5(TPT)v7e9r<^HBX}Ma?afqUkN$H|@*TblZ{R%zYhj zS2}+>emT>7b*j&5P(+%tE*3%G#Oue6#fH4Rq{$cE{z@FN8(qwZpK?>4Yd+>6$VCWu zwwyj^WkN$(5xIlc`5>^g7xBgJXo~PA=tAauSK9gp-bCH0$CK2h+p(S9h}fLQJcHI} zIt)bkJYc{(7{@YWZBZ-7f(*gxd{z+X*8yj< z9hCV01S=fW<4zi3%?wDFR%54u&+>Z)X8)$m%W{cg`3)RL6f%~CQ{n)@mR%k>^1*+9 zwS!I(`U5~nhJ%-O81PT)M#Ld2${36yN|WP-oDY%Y=ji;fO!0HYEn@Ll^O(qWo<_Jc zAppB4pa5DxrN3O#Qne77h$eqB3^-;a%FkNBxC~AfmvU|DvaDCG-=(Z`dLvY@VE@zv zne@1);Wc}~C-VCA4>cXM;hwzTYDlP~+MmOJ%WDXviK7aXvwvb5BcJaC@;X)fE|PpL zd>Cb?2iHAR_HD@jJKYE^>^u5&hyj|=LyTMqd#Iffr_Ot)6?DEAz(+AQXw)T=jwL9V zU<8+>KhlV;yiCJfL(hXoUD}u&mR_bN(0ktzOZHGO#(a|m>HDl|awXcuRb30ht~af*>cRxXj|nDnwdtXXVU3Y3-JW)MRtj<7a{H&IF1@8-RcX3qt6 zQQLBq1-OELA!wD%=}eU()u#2P4MO_|ujE2@xExn?W=_STo|GS20Wv{fqlTn^+e~c? z_?QXAlD_vkP7WV->!3$GEL-vE0pABJXskLx9Ru*&%hW87s3LiNn=J%N^-AYpz7*3C z4@W4+C)d527%dwn-`W~iQney3-8JS2HPVO+g$R?Mb3^KfZPdv3phcOv`iC~leBA_} zPmkCXit>_OI|5o7WneKRaEgL|qp;P8KP})S_oG|QA*BDTY2wpZ>C(4QSDr~7O~B$< zx){V@D^?)dwCV-@qvNA-}-cj67Gt$T| zN0E4E!l=e}K0#K`Rv>kMwtDy%C~O@dAInh~>)SymHGT3>|5JGJJ&-2|d-PlLupSf5 z03?lAwFqFN2&lgbG>Z|V7-ToJ>XB$QdRuC^m>0D6rl{Q^gTrQh{AiU6;S&8qss<>( zD9VYR{VKuctsDA32uRGy9T7r*wv$#9oZ~x0l%=yx#O7qR^)<_XXI&X=IW2k{v`l>G zJLKEF?+X9G<}^RKtvHZFA6d_3m)Xd;a0&5ja3I$qyu~0gjq?)qWXmPa(PxgO)$u98 zG1xbIjwY{8xPT4NpJS%zi4wNpKiG|qFF30UM2BEp5NG<@EQT-ziF+9??=PRHV0JiGhq{+AM zbe){s)M-LHZPm&S1TM8!WW4L-WFo+hp_EWQCIVE9Fb?v6gEt#8YA_1@Jhn{~IoIta zXiK3p$T}zs`Tp$2YRfka!P4oRfDyI<*UjfEMPWoMQs!sPlT9y8_~;AnU_CTYj(-@m zbh+58HT~tWi+J)E-_J?-H02VQ5kvMh3EpO_wEHv_6dB!7QIvQEf;wSkUc$8@{-sSJ z)^G6q+Mb(#izt=`&so~UsC?(Z1s6=>m-kmb(n(0g+;H}lMb-Ye-+KriaOvi$qqMPy z06Db~yOq6yYc;u|mGR61K9U#B~b%##(ssrzjh=q{2$)Yd;NR~Zd|%79y9pJoiQ8S(3}ZhL{5GN*2( zG1b@{i==|leFAOd(N0rR@9OrpwPu zt0#JY?^_AgBym|9 zGGu*xAs#^em}T4t&AHXbMUo=*1&;zat)RYtm9zN4q@Ius(rx@MtDE5rtyiW@!3SU< z-XGthZPt29vv|*2YzwvC{a&H|?*ReT;ld$q|{&p_0!ecwn^#_K{aK)rJ zNObvhj2~|pU~$^8$|bb>-qdV2=X~67XJ1`7#vJrR=44)En(JV0)gEc>5fjf3QIdXt z?CB?ir2uoH-u%3~%yPv(fdy~aHpW=G#@tLa%}VUn*g)>>QHZG7a=!pP!?1Y@pZ;eH znlpuBnu-PQs$YQxgXM*$XvpyWIo@``70)^$XjOoRkQ^^{&r!z-JrIBTxy#*J(8D*c zTX|`7S&wMn5*v0xYwPzUQ^D!_x3GbK0W4@wQ4hNFXog5Tu4z?!n#Wh!v6Co)DlIgU zlO|3z#5Y?e^~a}7SpsA#h56GUUq$e17$2fU?b$T}jbUy}@jUfh`aUIyd*e_Ln$ex* z1bY|j>z|QfUIRjFVyrM7>)o5xVx&#hv5S)5h$R8;?WhhgWQakfBnyd^SKhFHEtWS{ zTTS~YF>)tg>tpXSOdKVqYxvgQADzolFqc&_B((hL1Tb~G-id5oFt4nu=~K{pZZ~vVYo!6(itE=(-JcA;zP>;6f15>p={OrI$rv;>Ugp-fMWZY5f<2aT6`S0mMHfJlRrzZySjK@Ryh+i|LI#{ir>IbNs zw>`r3N1cr<93Osy%41;!H@asE5HK38HKVOEURZl@!u0FVTiodOsDXrk?Ma`@C1%At zKGq!SiMEGmVGqG=*5Ke8?>am?{Dsb2dWd&!?8wON1r-@Jbe^G$3Kaip!o-8k$UO7{ zeQK`(S4aJ4^;)D}pA>IL3ORhgh{le80Umn30n`ViXtUFZ5!e)yU;i0gZgo`23~28v zr#BSN-HC|-SsXp?Cxab-$lS-6JpBKpT4flhjUxFi>^Rex;h^abd``vuRTZ@Dg(@0J z)v{OpwBXeGha|sHI+I*Ky3zl>x`WGn)OHnzqmK_7T;jk3i`|=I<);}kHL;IlpuqPi zV*Kl48arqfSK7N$7a@M`X)3nI0Q_!Rb^b_dR_bIsR7_Ku?rSxFj;S$Dq15&dMWJeP z-BAae(~_LnW)G<5El|U{5o;bn+kS+q^}6tz1fnjy%eotnb8|_GoR#P^k%hLS%MT@2 zo?h=pN%M4o@ab{eKL*glyQG8je@K*mFY>{5&L+Q_nhoHS9;;Vc`E$P|RDMl%MrkF7 zEE-#+1mufbMG>igZwrxSLwonEhDk44vb(GAy0YH_=txY{1xh45)f#oxwjMj#r@X5b z7enrg-QecL>F=rs?c3SOsBjx1P}?Y;?QdAv&%;)5oXYk-xt(IQ&EF)Z(8Z?xHns97 zHD>pYNBzd)Un|_XMfK+$%lS)j7$9*@42F{Pd{+nz)9Xop7na?5zz~;~>(_pWNY?W% zX;NMf&FZ2<+1PMLBqq*|H)LCdk&sq^x*qrd!dbAZr@t`b?Q43Zf!4at2U+1oR1{E$R=rk5AasD&_Y~2h-45I{nX(EA2P^f*A-%8az78sebZpL?d%&qE z(=18O52j;(l&VGyfE~{cufAUsIh*lmCPG(87}(J!%x!|ywUkYaVxedd061Hkd>4E*y3V}{i9EU+pu z4Bf@gYKG5Wipq?k0I*KUX^Xn2r_6JBGbwGt7JDLpad>l7EZJo7_-qi7Py@(?<#*|> z^|peL_9h|7*>{xKG0@k zejR-=l2@-Y5uLMZqLebmc_kSTjI|bK9gBNL76%md9A*r|p5IJu#wS%x2$X5Hw!R9QNe_%Io?F|WHt-aK|`<0p9DSJsF|oODt< znp%XARpXz2h5k5wweyeQr($~VGgnF+&{L>?m94$xn{HN@JD(VMgMh}ErhgRzikn~d zJ7!Yu>Ge~?!VIa=t&C2aHc2M^f+I}rYIl}0D+^%rKPGc|-&ajtI|9|Wt674SzL%u* z@~#lDfIt*lkW0v%c3jNvc79neV&Lc+0n!G@5nui5URgUEaLud{>VgEV-j^=}iX&`) z>>H^~^vxX=9_(TXvDP5xOw*TjKge)82~x3*C^&5iYb8-|AY zkVSS8)s@|f!!75M6z=V`BzHuEK&Bz!Vu$lUG7(|$tlLG|P}^5_&0?MrdA`Cg4QNSX z+Jq!g4=YT2YG;GrOC%LYw7cpyItm4USTjL*zt0==Qev-dn~w0+b6%RZ}(Dl(bV&W<&qT9ycihk%DlfmfQ|L@^bV;i5kJ0({T6U};&9l#Z`Y;k z*K8Yo#&K3Hs5z^%?9Xr7Td(>-{=_>4?kPEWZHzs}!~$p5zs?CuzU0towr zKne{q>TIgSUhQ4cgk;Zw74{K2Kz$XNvuD)HGFG+t+r7IT;rlBL3oJVJZ!bEAD??MT z3jj1@s{K}_TQCOw?_Fb_5Z)Vr#>QI@8uMM4m~qVJ07Bz{&nC9zXh2r)*sX}eo41{j zpmLzINgY7%m!yXsyWqJM;;7eu8G8?XAmPlXa({-8Tq)kUvqx}te#D>%^L)WMag;Ru zu#H7~zl;CJu`PuBfSjG2uY@$FuxH5E{atxn`Q6Xm*yc#RoR9|I@(yt9ghL0X+(#iw z5XoE*auPPGY|A1u<%OYoKqsk{*_tQZooev2lCft#lpDjrFiSMa8C5xd%86|T$ojno z*!uxL#Y_v1bD6VWadjPvQ(gVvl;r{33^8>K=^|-6Jni|(hTRP}-b-T?P|(QFu5`Up94hbgCv zDoX6=mGV*jl~6@C82PQvCRe58kKQXMrp+7&o;5Ew+6``5h8H}pyL>OJTgl}tn8Iuw z4g3;C97`h%9F%B(3DEYHUa&kwoCS2)_`{t8$-$cjj#|pJzn}_3|G@hxO;5jx0wuo6~tdPs+_q`k*`KZsO4jF zy1Su3OdRk5sJvJ4#X=Z{qs1Zp}S+ zsxooB^W(b)_$r6zwA=?}%=-ZV$m3A_um}HSPfxPNL;ntfq4P^OWZIZ&|F9WG&B(7>3)3&_{=;TKr|gg?p7{jFqFEDcY@5}7I#xY-x+DR}Ot0Mhm} zU>P--l)qd0dy~#^q)XS{LT@-|!Ui8Z;t5t_%s+sxR8@6Zm^@8xZcKouo}{egbT{#3 z?g4XuuZ-&D4KhYg4)%ADnw*?i(R^8@ zCat&Pf9m#+H4D41p^mqf!M6O4TR;pL>uoRGq+}4WaEwPR$I?DC$;Sc(g_3l!;E$Il zkf;>YuWSC7VBfD%k02-@f-Qj)u@{>*8{;Q`E@o^?cIG+-5JG~in~4tfFG$9fQ0P}P zEtq-!NpL%$V(z9js0a@LpM$>!qH|^W$yWz|Vm%~1v!(s4c<$lJ zZtrjf|G!m3=ln^_6_Zc$zz&vp`lw`~|KO69@@ipmc^*b4?W?Y%6+WxvX!2Ho@D%QU zc_5wBU#te9;5W(a>MNYW=4gTh6#b3gM@;`=1flW_2-iMN05whui;zE~LIw%N04Q$n zbYzU9RWuAe(xL$a^F=Y|AMy>8792lMPe7$T% zGx=!{ZS(qn7}ohaXd?uA@8L&FuEiR>V*@7JKzL_T_bcsc zR9Q#?(b{z`(At0{&C<0V9O29eF}-wF;=NHI-K{SZQ zz<-ZaCRg$`9i~8&!#v?0m)t<5>Z1jp1jx9XJ`0$X!`3Xiltir`7+-&lCm792j|zlx z4Xa%x`y?*&wqmQ+U@BdH);-o-1obu90F1~IG<(Ot>>mN|>N|#Akg^E-nE894Rx#mm zjGK6kAm+m^^+@MV(iLq!q&bIwx>!_2ob3N-2RKuQmD@+wVrVjQl5?XK0Jk_miOi>^ zFa5!H*b%^j{GLj7Nebk4Hh63^jp!+O$iMy~=`$dxDlAmUT?c}jj%W9|+HXSbC3!Wy z7<66YnL-7>iUyZ6J#0m4k@)+BZZLku%Y=AOF#kz5h;TWFYX%PC7RfAsFqn+7Xyf_$ z8zdj1jc$P^%2dw*Sw=(LRQf*TZvzJfT0IE%Q(9Yc!B1hp;wfVmqJJZ$Vi91`TAa{%DF7vXVof=6vG|S@W z&&?|VC5*wjI@@^^q=g87mK51Y_W#*;b!=a8go1tGPzXht7KOAoOnpZzld~^)eg8IK ztt=JokWq~)eV|A_IC9&wgSg??NKpA5m99Zn_5*oXUtJ6Y;9H5)V_JB{7I zsd7GBzE#nah2BKowo?~%to4Ng04x!Q9Wvfz7#B z^lB#bBi^2e5qy@28i2=OMH=)8^+dg^v8aHz2guAIz+2ha>582#C0_l46$8WSbq3rbj?*?overC*PrZD&t-)m`C0bgEV==Nx zn2+{?zE_U-a!#u3e^yp871?h6meE6a1MD>5pPaen>;adqC}NgL$Y1zEy#2m;;RQ8? zG-tHOyaL3wyy)<3j0%&RGsO2-vwN@}l5C66Ye%2Pc6I4G*`1uw@HwR2#1Km6#Co63`$B`qs{tuRv0q@ z*0G;&#jwO2xHRJ7xdBK$waJ8{*Pk{nhqXvfSL*&wk{(UHHlPJjOYv~di^RRR* z)&A9gy#Uo9>hn&AD`~ZD<><%m_$Ca~zNe7ytHlmAI`0JpBT`WiJLEnl#D2`zqIqQo z1%kZ1MHzZ2eaH%kQnVQ5&w7CO@w()Tern8x7iib^r`6W5oI}(1$`6%P583zuUT{>^ zutJlR_Aj_NbdBt^uM~()ppZRlKb1}&3cb*OOz;SA-sZQ(s#NAPBu4o7h$d`>`z7ij`F{_o#GhV&@EUY>0g5sB$CQntH;vDRbQ!U2f% z^;CME3t^gTKD(xs2d1rK1}><5KT87h$LeXsxY2w$c5_|SR(Ex%eovDlOXOrVcoJ&x=(^~LZH!C&G&+?`5! zEP#S`E>HpE4^%cAhV#vR>atiKr9|>HOKe6OIfPK{dgw7PmgpE+Wi)!M>&)M^4Jwtx zJ>(!~9^{wtr~?xLHVm!Wd*kc%fn$vP983x2tY5r0mxdoK&$|2TmWS_42-~Klz}_CJ3(x0k*GNT`3hhG zu>yF6g#|f&n**dAz)ld51q`5OfwToXpdx}Spa2~>2m(gB|H}n`%QIUf(ouw)+tt;T z%fbP{1$VL$XXOC6LXfrqZ7>4t;ynX2k0oN0yG@Ku)ma5|5D%p{Amt=hl}TLcYmyZIfB4`8(V-t za0f>Vm^%b!1F(jFK*0bFc~vf?8J|WbDJ_5n zs=`0@AwW(LMq1<>miM^#9FB-Wdx0Eob>l z;r}DIaDYJF|7f6?>x@Kgff^jO3$XuHH30v$x@us5D~Pkh|4NmR7N~8Ig4v)L&B^nW z3;6Ue9D?AJAa^mkC9zhP8!{?X?D8;1W=5UQix4i=6G zB>Zm(70Uqvb4L6V9R)Z;kq}4Jc>cCS#fE`xem_PKPz%IAJwr{5+ZhJ=wN-y|{nu?)(fKBpPJ*E~xdQN{Y&rb7KT+d8Iu(&ZswxAIUU- z``Xi16+1&=@};!7RmG#BRL!}Pkck;DDz<}*QMVVJS^i5YiaAI$x!yJDBhK7`A19qQ zU>YkprOlXNYWN!QVZ0VKp}8@pF>|89%vG>p7vI*~&HU?j#MX1+U4R3i@QjEqg$fxh zmEFFJ9%)3!u!0;kdO;NPz{xnxSyxGaZ|oX95)yMR-5N#l!+p&-CVlYp=MPzZy{UZ1 zc`DtN0u>=76r>)?blF1*{S;*JS;`FvG$v{OGnta)IC_c#hY+SE40FMy%c;D+miT@? z=Qh#&yoQol#C>rN*L;Nb}P<9PdK=~zv+dP8PX=gPPZFBv<`NK9>Ez7sL3Y%;|$v} zc6)Z>8${_4x>Mb%|$n zRkzU6)bAOI1WWl%5fPBsACyqPT__hAek~TzD3&bb2lQDSKe{8UwHHfNy>?%#>&IQw zI7_D^ZeAQym7MnHw&q3Z%*x28agh4mxT|exqe=fG!I`BT=^H&?Gm>I|pBFjS(U&pb zw@&L0a}1?w!k$CJlR74S*Ua7wQ@1_ui+P;(etfUHjX8PCO|kCh8Rij*<)DH{KYdUE zw5&dszggyUA6dAbai4{1>uDp7Q`fL{{pk-p9^-S-r|bTXrrUMuhmMz}FQsJx4+xp( zf`$3kD%AX#ggr6w!t{NAW%0iYJ;1jZuM6OvfpMYPTG!*QLnTxe$n$oM86q1ah--c- zI3AsKKmJV8T>Y3^x!(hHj!_UGFLddm$@l3Cx1ol>2X`rWNA-cv?v{zcODfp_wI-}E zqo>P7Cn1f*c}B6*!+D09a!0DyylZB>P4_FBO5lpgp13>@-6ko2NC$S9J6fG7yjtM+ z7iT{W)M=@;Gvtzv3-{BTVyDngFPW0o(x9~Rx8yH;Rf*BHZF%0($Y)!AE36pvW)Fqp z%UqZM3JVsySa5hB=npDPeYMLsO-da?)`>ns zih@*1H3lYQ=#=h%N4=YRce(ZGyEgHS8FI=%G`(Z^TUx)fB+HXhB-?Ni$<%$l*IAxk zYu~?Xd0X&p$QMH~lG{&&+%U_ju=6L835o_%#a$JvqBV32`b*=oY3BXzw4qclRQ^|nWZIbi%UT; zC27Wy-A_K0Mc8KlfIQmL8oDK=bfIaAURsmxI-fyOXr(lu=wZ(SI_C>?yNsiW81UcI z8PwBMsPzK{2j2Kn6=I(Rvxpc;k8Rs@#&e1fgGHT>X?xrgSh9o|Cwxr1% zqx@!Q(bpw^eww3?p_blOuSiYev}RXgCDD;>CP>hQVD_Qdq9zZ*drg5bQ8HgWf#39q zFF9OyqejTOIRrrIu2mQs*rdT4REu8@6r9?eWF!c_7o>of|1&|`;|xG$}LR+;s`oq8*20-_O0tcFnvzGM!h z*u0|>cJEWh5`p0xO0zsUY7{&{9SbOI`8%F20 zr(VEY0!(Ka8knLsPL558g`ml?>kWt|rl6os?zq)eQ`QVR-HjeU3;YxGmGXo6@tPHK z|27?e`drc2?c^(GQ#74$Tq*wJbOC8G;>A1{*kZcw8cs!eZ1q?xeelG235f|e)(EGs zw`bTy-+*M!R0@0K;|vJFo$C^i#i%1}U~#Q>>dUleDZYA10NSA~BjQKt*Q0CzTGQ-` zdOmr;`bN3_!un``V24FXhRNx+#54yU`u?$hB{CP9m}W~P5Pz!?=F(+Wgr)s;xJEcm z2Vjb!xlgC%cz&-lj_SP0N#MM-Q?#JwdCGQ2-@3~jjj%nQJ8=woonnH!qbQ~9!0Z|z z(T-xDCu>~fNIS@+{Bx$Ihk}d*J!60u_;Z0P-F9`#h(PpEfwty0!)8O1$Zgw4)`7Nv z7`Z2N+XYt4<=q<{RGdxqcprGtxT$&pjNf9sL+3lFqUJt5#B&%5u6%w)*^{SAAT;*= zbUqq1bW%44C!I$xkH}P2Ecn>0^6B)XKASb|JNC{k$ZCQNJ~LZ<{exTGqvHU zYjaM?8f@SLeXMIL=F_aP>hZG@q)zdFKt7?B#OG>5GE5SdK%>Cmo^yM3gF2)4`|@+o zwxzvmQoh>PEOuirYwxoxOplrJ&M^`J(WS1g_Z)&+(4s~Oze2qn0^w61_DY^oXl*o; zRRra_zasHUj9qY{eQ?O`6PKSu(~~4u2a5UlZXP2+t#5ahyW)(Rd>1(vjB%xZ2+jzZ z*OaOK>Y{$IMXw;>jaRsbe}J8nZBoaREA=q$eN+;=*H#tFdXxV2x8(?h;&P~9fQmJh z0jbB5Q;ylb*rfu!Cv)l3p%6ngKp{)VqweJDkV6U&?oT!K^B$9`-Oq!(n!;u8(DXg! zB>b@gl-qZ#kDz?6^Rw|ps(&Sav>Yd_=EDlbT%*)_Qd4Ie653ups(77ijHc`Fh8R`L zqYl;#XRCb;2A9MZS{JsXx!Ny;KBBo$jU*XcX-Z>FwLyet~Fkr||jKZ!q_d*7UYaYxwWZp(&l zn9PzdcMsC1Ileb7Y>(i3_kz!dQDCk{IvDBjrrNQQQI;Wm~)SZ`+^`UN6 ze0WTXr-@9dIKvHw{5=nU8@ll@wm0x*w5hvx5g$3#Fa7sN3Pvj6$3n5aDy~{KpQ9bK z*mz7y2m-ifBEnvccI{T772Eu?9`rQEx^!wtm6w(2{zqTDr`IchALg?i~9A<9`nyn zhNY+%Snt6O&c^Q7OzXBL5qGD@Evk+#6DaQ<9)C5Jg%n>K7aoZqp1u0i$lFEtjdV#b z^ru%QTFMiwAN=}3yVetW5j!t6{k_kxCcVUNqcTvxXS(=*HM}&tv9=Kz!rzK$V!YQk z64`L6*=-!9{5YyOI>o%~%6R#SWd;HSGrv#cB^;(y)}_upCi3O_$}L|^MK#bg1k6i8 zYG`k$BiHGyw$XR^zmN#3CE01Z;rs}TI=1%ubuLXjN?Cd zx|n~#YptukjDC39;p=v;z;K&G6;!Y@#^s&cGC;=jS6cJn%t{ZIa#UOiB)^*`MEt8`6DnNCtl! zlpKYU6ByjmPwLAkZeP3-`e^@fI{xl6_lqobXMBq!?45$*wqCBnzC(1RdTl{Z7?k%N zQKP+ol#)p(>qE5*Lf?9wyvzxrpnKJLs8dx&T0dSCs89qG*4(TlWN7rw7E z7pi9})E=(fO%o?T?=2pAZ)Z~b0CvJ>D6X7;>me~OyYDBaei3}9%@T%B9qsw@p`{Uv zIQ_g3+jeC8z=(aZJKqI-HR1y86Tt5zTyd=nKUUUtwdukn-w&^iDvoT|>b0j_0@+|e zcciQTJjF^nF&6`w{>qjuB{J*G!=Az3p26hlZY3G!5y-kR_h%(hiwvegisbRo$tB-^ ztFu%`TBug#>qM>1^l(hem0~h($CEpCC$AstCcbQ!pAf<{yP1|EPUwK`l4yOzzRhz` ziScCe5Pde?k&Wf=aJ*&=5gZ;Puiedh^NpE}{Q9M#pY9#lG4dJJbd>!uH;zOJuLA{Z z_RyI1X;bBX^2%!7h5HkhwMuiw10x@@&=zeTD|IXM2)Mirn6@}Iij_B ztm;BDJCdFARYggzUSw*u{CB+zP5Ks<(U1`KverqXcCa9c1h9-H`3whQMMagNS}ST} zk1gE!fW=6OGcF2h{`UKUsQEO1+194iIF6!7?c3KYMvByyJc)IyEsFh~jjn5_XaO^*BOMDWuvC$=J$0k2S z3@AiNiCt*pf{D`Z8m@}o4U(o!xEEezND|AXxuPU0kwd4O9|qvM-+&WAQDN4e&(#;A*y2Ybm3$onntw2nU(%)jp)x$I>{+rE^R|c zSKnoPY9u<816#Ng#YVnb7-n7pcD>pCKEe3Cyal&;SSWvA}o=T>5=xoj-6 z*gZrR1+Fav@V||J<-xw~XPS(f^lG6G8$1fun2VY8d zlTDl(=76o9R-OuyIfD11-n4{A!7tQ&Ux8*=MCQP;)e>jHA!{Vh)1T6)gxQ2*mh^7t zca>}rl1N5n>6Rw}rkO3y=o$M|yv(&!yuajqSUYx>4arJ>3@7kDVe-4~5fbLQo+)bC zvZQp82C@6fb+Aj|4e%F+F+qh-4VyH@$6+?7_mt$fL?pV9Npo>nI(izTpgsaSUKt1D zf-hwng5v)620!f!@=Ds!hYTy31K%A`7m{ZYl65`PD|$Dpz9^&$x3XJA%o6Ysg^J^) zKcS-hmNJ2VWHwB;A`@np6RbW`U&q2pw~7+->@_)#a%g(R9ZGS(?;BBe%WMo;ffc0- zMWhjW2$oUG*$u5L+>zw;YdT%JT#x1}L3s)Iqp==4O+w+-;|luBPMbvOh*wdgz4Mv} zF{h%^rdqKYC5e1LI@qM|^VI}8!&)#H8kUv%2zG9NbIdfbz&GX}acR>S-Y=U6cykJq zX>s=yY^c?M{jw$II{OE9Cadc1&=Bp}u49-)6j~m2+`InTvQuWZ!~1OFVkD)H9g}De z`M9gJ%6KfRI*dX&_ohTcGM`Z`UMXPdD?YNYZq5ZOFl71#WfQmM+C=xUn!Y^QAdvrd zl-*u`X@l25Sll|ryQBd?G=9-jf69jptuMQ6&b2EIDeU&5FRI-nG@B)pa+-=nB6j6zA+b>YeekQL%ytW=XcXwpp zw&;G-bAjZm2pR6f0i;T9ZDiY3cp~1hb zxgO-&Z8jb*2aKRoS>g*HAEGzinD}Ay@3cT01<_ocm%I#|AODf2E9z7KuSx?H08NQhUxs5vHKFP_UK;|1+PrLOTlXa>vV zFaV4mL9dXiM`;(mT!t0o9&vLiM>r57Z8%b9a>q7nXp)TVcU!UD59{C?%X-o;F_*}~G z^{;AVx=dC+uIIhuf`{wzb3?ar>E{q|{xhlNle5e_#+e@OV+qp?m|&jrMf+*~R4Z+% zJ#&`cU`fw7vAgaD;vGj}>*7D-E4SPwH+yfJ^j3c2{QgU!TT!$huiS&dWS_aLp12wL{PsBfE)9|=#<^naI*nyJD zjF_&LKh4dJk;Lxpi0ukKNHThqUVC=&;b@0LiXS$pv@9Qy%$+51H5`$?f^TAh;Hp*U zzLA-3K_@^y{B*4ttiTU{bn^yNTMFZ(>QFHK$STMA>JQv-YX4HETtuVj7k}6P6kWaI zMTdmxQ|5!LZOf8@mNDA*%pxk2=B|#QF_ zxb!(CV7c|CMEf|5ky|~kUl*jq;C!VdW4_4t9^M}g6W;7$I=6%5hth zG@`_M@pe{Ec=(o9zBnA1(6vKJ79i#xiZ&G z^i6Y?+K0UC#oqz}G#C}oM|t=Qm~XI^tiw$;4(thkd=~ez>TvH{>CBxiZuN$nOGaL( zIVu=E;8cFi`bgG_vL8!b25!RYL5_ODu0g=_0Sr~(Kl`7q#tu0wR9k+#DF zZx~b~v}I^wQ{P$yFnn5eMb$ldeV=H(cO~Hdm+c?*mG?xF-@|aDaW+1h)(#jfhn7Xb z1D`%tP{3sfK zzDErC8iCzZX$3L+vlzIm0y%OXtI37-o`#W9o?qW)gvEjL{j+bfuhNfk4-5f24Ons; ztH&LwPhmJ_MMyvuaWIW7dDZ%DdYdJP4#SSjDra0 z)#u7e0+a1kn`Vb=je7!UJ-cH*!ae1GWlKZpqNDuNk*m>Pz_UUEQuHz|>M>LJCD>zi zt@g4Pw?PxC3hhANT=$9n@;k)!8|`BGnTj?CyOxGFhK`!RJg zGs+0&b@ne3c*^6H+H&9A1;b;Bdg3^I$>=gHx8w|Y_|V5k5NtE%Lr!N}if`n9$xYnR zE{WzgzifS!|Cz6+s4jk-Y}BP16>sdYgDh?(+c)90Pr33W334=a(Il7ISt(sLkk$T_ z&}~W{M`fddwzrACf{r&iKW%%Lc;!y9lE-6LnM0DS+7tTV)GU9a6IHS`!7a6qH^NZ% z>(j>Fvx^@Q{6VjB6gFU>0SJ44^ao{g?R3+%m1)*s@m3wh?AhyEw;$9wsEv!leR&=KBPi{iDF(kl3l10+_1=dGXMG> zPNW)HjIy{em3^@)(Fku2(bUnaTe7;t=sR&n3_|8`YYYG7k<<(1H zfoJ$0yhpB)L8BT6YXy-feIq+c-n&~tV;as4R2X!wgrH+t%~5T+*^2r@#;TO?5=NMn z?Hy**&=50iMpraDH>dB)AopA?ZF!s9rPay^ARYh5oIymW&nV`H6{{<7q~hj}u-*^s zi3gb9w>wj(v`1fmb;ZVT3*_pAq*QB`(0wC28U^~jWkz;O?43Fu$!&W`+LXL`N#nE& zL2K1Y?0Q&hf%%aFaT@xu(<|GLw;+^1Om#(}hlzytjvnD?9-EN_(Q_=bm8~j5&!ZJN zgR=_7*WxL`BCJc1jydAMV)`xCvbFH{!Sg;KManx4k`{D-`#WxeUjRkMVr)wtzDTM2 z2kvi*Wj4-&H-kg%y)Z9t#)4-c&V`>-?PHK2;_fn_O zG8CPJjE|;kZ5>Eh$bDXvo0;z4Hli?K+|evA(-~}=*MK);IPW7`n)ehqK0HLJn^fI)^QJxe!~1zsoZ>fsd`>440yRma4$j3lDL;5q3jYdoc5kk8NG9?=@SrH3%G z$X?%njGhJ$PqQ#Nu910mjf;KEn(T9~IXbs~S4|`stx=e*YlFYpp51QL!2!%meLcnKR%Wr@n^ta&a>8iY51)db9RC7Ygq96`lPl~1mg5s?li)Bb6VlP#M!s)B zoOf^Jw7YUpR1i+)v`V8|3n0 zQ(0b5u}j#@TZ|ALJ;(>_Uad5sT51q7Ae*en(UfghA;H9QZ3 za|aaTM>nSlkD)FE4j8p^tp^9LhgrlB)~cbopbKL!C9PRlBk?{rc++W-UksgWcA{^Yt1 zP`3j2)I6{<; zpm1_=Y(3?D@}op?)kwVhcMR}h(zlWJ3R#7luWG^r+fDa-O={}y0R{g|FRa9_HawqXiI$g(syr9ySPe;yGDQWdEM8CbZo9N z0X!;FR+J@SJP>~(uq8wKm@TtbtY^8Fbs8_IqRp`hF`65wm?Q>V`5($bPV7!$9Vu03Co>)4J%19H6%6PfGg zhS1~BEF)Ot_hUpXj{`0LaN{2>dt7e01is(Pxik(IzU{BCuUGj1d>r5KASLgDAPJ8z zU?R&XqQa+-eS6w>YFDzao@WL`B^T5_500;%0QYX7@|JF|Dl6)bv(X-#h`0jgqSuW6 zzF(I+u*deDTOxQaoLP_je{0RI1$%kCo=zzp z`v5DDvkD?l_QU!Lrgf%I@dSR~4+A3gfIAt&9uzo-u&rg$p$kxZkMEt})meps&xddU zfCpZ#$?aF&xqcbLd*T(*Ykaf^t|)Gb44WRDDw}R$hh)vvaF%?;l{4GDH&34>N03pT z;P>lBKLz$m9DEgpaWo{{`|V@V$!x^ulz@+_smYVcvV4mz*WQZ7vpyeP>J>R! zazK#TU#ilw!e^HEMUD9H?}tkVM)}-4fOV*JlfSE5uXkH}=N?UFhMVbN1&g{A)}(1! zBjq5X*XUrOr(>TVjW za3z8I31cRGz_J2i?l0j=n;ks55#3C&-m*+=d(mK$Bcv8)uQ1#*Rcl-e*OYS=kENyM zKcXK7u^k%e*bILP|FLEVw;6w`14?Yoee?3xTW^vu-&M4?5*Gc}R~d4f-QG`bWz#$W zrESfE7-}G1R`EZ&wVW=?xaHH7ocAS|d)Pfsat#9qpYIR_E<4GtLAO4zJ)EYc91%~E zx%B(a5U?8y)SRp-!NH?6RP89+15zxyugqv_{cQK*Id^@4?@z$UHH7*tfOMqQ_bk}1(Nq;v^@zSEa${C_vlVT^@Hr-02~O0AZyFt8T#wazO7esB zL;mLdPo7ma$u7O!dIPTw|NMvq#3hQ3}V3rfzBVH27sc++$HFQr>>g$R>o zwn00XX)Y3h;Y(cx!~tawd(xe%X$5jc~{VeK)fbQ~s(5p_X}Y%38}T zDbXHjT1{(JWKtb+(%Ohi2-PW0lNbjLtic|?Focv4ghMKkZ-!-|f2rT*Z!5S&-CMtn zlk`xA2^_XZ{Y?i%k%nX{q*p8!H8KQ&H0y~`K(;j)r6RJ|3^3jzI2>p#Vi~IywD;J! z;Q=_2JJXN%e>ak!Nk`kDw8SC!OXGbR$_QP+hM&H0?ajAmNj(0_T;5oB_if_@FHz_` z(kz$xPMy4Kx=?g=Uwe*|;VQB7xRe})sy+^pr02)1Mn+fJ*dMl@nwZ|V+$RMousu5= zl*V|NQZ58l1N=@YIw?jasfdIgPh-hr>b;_rv7pHyC9xsS0vmJ9aD$Sd-ChWDwV|CA z^qGj@OH??Pn~?u#!{f()U$C4#&)8s5t{%L2YBt;PN*pp0v#xRF)nHS7E1@T+bGi<* zY)p*@wT{-E?!LDM9+*}5JvGwn=FRsXU@UuL9}m#k9w!8Ka;LNAYCD9_TZfc>}S>N+)1 zNy)RTkMVqI@^bxM52hEK=h98JKdWWs^nrKf?|iP@^c6u3wQpXh;+m{kBz=h;v!q2U z5Y^`b24Kcl(HTvA3UBP|Y9$DXG;^M&pvI5-r!& zm2s~-Bx@Nv70hw|$4D2YZXYI2T=$7&1fWznSUePM!vlstqaebrSI|u1TvEJ= zkEbT9MsjlS>aL-`{d6WlN>n)1$WK|YHg8FAS>eLs@%~Nhv(aB|_M+|4>$BGW{CM%z*-=BHM7{&Qx`V0CrcyTM!ITj|@W>8JDh&SU4! zQr1YBw~m8gbyn%lS4XA8x!}dDM`h*?Fd(trgMGrMG26hFMnj)yyRYv}^;3QOv9(ji z0L{`)rsTWyPaa(=yx;MBFZjxEVk&7q542FyHi?j5b^rk?7n#Y7iT4_OCtYKul3Oo=%A!czn)CL6@HE=)H0I3Uf}8I1;h?l@FX~eRB-U;jYRcPO_7@ENuGB) zh~gS0f%z|(X?VSNUr1E>fx)fffe+TQZ;$?GN4&Pbbr){b?(|LC{Z;tem9Ji(-s~*y z4EPqU>U0_SX>BX)VNSFgD_|@$F(mc=%H3(lR%6w7r!}}LdgRrYyU)ArLcgZ9>)Kk+ zV5W|9Q_ZiVUD&##Tgx7Eb!zre&4sxPPK9M`8r^x_o7F&`O{n(T{H-^kcQmqn=2@4v za=v2a`}S`?b->|$?3E&uK^FX|GKn#Z->$QW?x#TzB4FU{7}{|Mqp>7N z@87yh7EIl<+iF=P_52O!WGtw4G798wCLWE_g269210grXdlSa1ygi~alMgGOkiJo5 z|5n~%#=416WQhCeA5}{|x?T47fT350FdR34L+iWI!&HbOJluJ}%ya?#f)jMV8uRK; zag77<_CcXbS-LVrGGGzlduzZD<+(5baCtacr{1=#aOAf3P0&kk56^3NLMD?2L0B%vAFu)0BPnLkL5Q)niqiToO}*wEm*wr zz`fEad>{wB+ISdPK^d4`_Pwq7y>GpyA3inBHr|$HU7?g51N^W4jvN`w(DnJW^YpzN z^BRbl?b37R3mbX4G5>T=LDCr%Aakiv-R&{Z-Kx&YC@q-7W$}0kZof__A>PGx_ITN3 zAi$}2zZw&97zKHzT2{2)#q^QPj_F7EXilMk5_cQ~3$&`s{Dcl#@>k|flxfTJ@P$^v zGGsZ2qCmnW2Sj2q7mzDPQZzFCW^QOwjQ_^>?-3x-XeN>yFns`0;e(5`tU=iVk@gS| zfXU&dJ;kH(kdGe&jorNSEWVR+R2EW6lHG)R`kMhRZBjq zXoI2)hZ?mKpLQx?&8#>#D#nOA+ux=~+swX||-5X-#Z|Ege@^_8&l7m!4!26XmBL z3-HV~8&nE0rJ_w)$!O+@QtvBh zxl($nU<{_t!r6gWSlfKHvu zHflkotK}Y9_+F%u`_1|ym7(ggfe)8KT4tz~-(!mcWJ()Eo81h7t|hC&#ldMB|>sR*Pv*e862SiyETzupw0TqAfV0E zZ7@f=+_z*~65YQHE49{>MQ0}0Vt48XahgW{P07w%&(`0r`**fQbZg^HvBjG(Q)TyL zs}Ds7h9 zN`KAnuBNjkvJtgyGWocSU;sowE0?|oJu?y-i7Gqc7KutXVFrjqg_}@|M7Ei7G{Vw5)65xJl5e-Ur#=bE za;Ia7i=8S>*?-?F>`5g4*ZlI2a4bIv3_R zCik%-)V`0g|G}6%C;fp?DCo>(hGxC*p8aAL?8qtqQAr#V%zz#&6-C7FDTR25)|&+N z4H~648ub6Ncr5>u#bah;;`&b(FAX3K3=d#t{$JU<5{*rJTuvmv8x7e!Yr$mg#33DI zEXnLncqF#SDB%!$k_6f6Y)A`C*^mP}j5EXR5Nkd7x-XRH|$0Pq{)vG|=(e2FMG zjLF7WD4c;wU3o4Wq>@%yaQ?}Q%Mf5?8RlTvO9cMSC*{Hh4W%+E)|_}2MfUEfq;l>r zryk^}g*$_Rg^<)3!W;!_hU46`9v1a=2MJq*z`;_UmJ%Qj5i&`uWxCs&&vXq)sUEA^ixzoCW54CCg8F#aH8o3xvv zWShVqAMSODWrt&FlNB4M(_k-2;t%QCgd`|IibG*f)C-RT#tYGfH4VunV{%e+Bo!TM zQJ~ZDqrv_la9cqB6ur=i9TiFTgpT7z@BGHfcZ5Dk?{ zbgowH;XCw`1l2WS)WU;VmaZm#q5~drkEH8<*`Gkg;V;Y4^4s9N5un|Hnh=)ZxU2Po+dudqrQ+|W}5EKj=WZ9C@s1!{!q;R!PYmZ z0DD&V%xg=^6kz`Zf5c?Z*|Jt*y!a}^o_=#$-SzvPbAOzECcOERp0}m_FCh(EM{!cR zu-kZwP_Qp!_0cr7%)fuSSt?egtXNUK95K^=WpVKg&`jX*cfv~U>PMzwRgV`xFaEuC zinirB<(jYL^R?Qc&Z@CKC64jD^*wuc+NKNfV*R5s&(73QZz}86bAgjEvvYH})}=Rx zJ;~+Gv+XZ~&SD+U*u_L=tYA;()3h5aE-XXeGMe}CilfApn_T$gV|&*Y*gO1fw@BsF zW|OxE;JzP^jX$wV9|iKNxXdWX-ev(M`pY^|i>|n1A4HQ5C_0*i=NGIHs1BWC(Wwf{ z?q(4(&Cx^owb8)o<2@)2{_6K5=g4Ef5{C$V*d+DCWtZ~D`M|RPRn7rU_i!1Ai3DTq z*vVrr*wuDb5&-!j@L_~qGL2UQZYkc;96VYbP;+QLKwm1XJtTn7Mq=iGXwY9dyNJ_B z{K{E~-+B6ec9}L`o?EUkZN^$No7rI9b^p6sypQ7q^YcAkB&9cRrq8#d(gQL)uVq_n zdjKUe5Cii$JhWHq1A)`Zm5O0V^CD#|v=Bd2n*1s+Wvgf7ujC6bfKBiW@~=Ke(v*$} zfHJ8SAS-{ZhPuIBJ3KNtMerT#HX0hK#jFGeErUwf{G6-SzAvjyfYLFu$eDRTs3cLP z8Ar3H?=D0e-++{z+)X*v&t?1Xff|&zj4PR?NliXnxPE!^RTvhd%(LlZoq z?)u4o$GLqyopCrwnT7)c8t`aNdpjW>IUO5&lamE1ttnF`8UgCfBS^2(FAr;%7+#;sD@)5)422V zI3SnBad?6urU5~H0`!{~*KU90mS69Ar^!=hRW8d9;u|bwCU*!A3)6ZMT?N7h02)V} z7F496_7q@|p{2&KisND!|4pMt-Bgu)ENuSw?&~fT0cXwDwg4M~BP+qrpZ~n3l(T|g zzJ|R6G)b&UU9FYabY59{J;q}G<)+kxnKPTMqcj1uD`X}43P#Iyi6$$9Zmo#h?jaO% z{ddqws%d$VtWt%5j9MZiZIcq-nvuAAVyU3>?FKtx;SOJ5D zn~jKxNSTOH+04bk&Dq4vg@}!bEe&`D1UFn=5x7lV5hRNk!1}*AyhUBd;erFsf41(n z2!5%OT&vY}r_~*w2WnXMZAM&+D>FZdg`JGxv9Z!^ zaT3Jv$;A9>r*%$B;DL!ck)D_$gX3M`{B#%dGFY2i3)<|H!%Znc3Yw1B zF9ZmA5S=#{zuI2acfL%*h=;V1}VbMb`)Lb|NB_-n}^oV_2{13xM5z+_uh; zRJNvom~?1stf%G%xKY}dtRV&y%oLLx z7sTj3baa*FbMyJ+6++S9?iXVx;G=3+=i9hU3ozpfI;o&Mm@#r|ju8~KzTZ&Mz$zWR ze?Lxpq3y9&xyepZ-Vfv!NCBwR#VkbwC(wjpLXoi$J}g|li&2rPG2R+NX+kWehs5J$ zGK7@O`U4~xGs`}b4+i4@#?TVUzWWl2EhHD_kB3AHv8VI}&in^OW@Hole#MHVD)1ac zWvKRnX5@(=7*oS9vOJsR{LZvjsT@RL5PfFeuh2{G$J31Uq0{XqkpPIrl+K!|&BJAY zjrlKf40*FMbmM#5bnU#y8&f?Qug*7mJs9VEk|g}i89vNR*DYPI0`qk7x$jqW^33hc zm__nIxg8oBZUNb&`BAXzo8{7v<)ch0>QI6C%}TzdeVSZSbo}N&6})NwMEWuM%Ou$o z4wZ1E!A-R|;V6DZjp(axtJ(noK-4hL}%Ek~lZtf0)u`qD=9Sl?F+BK0Q^G zp?+?#_^WWYlaG@5iyA(AJJyQqX1;$U=OsQNdojQ}9^z$_Euoi42nXqa9Y=C{w=_`X zHO>TxFR9K)u5{Ed~-*Z4!DqvXY7yuWNYEk0iZJEJ^M6n%?Qny`KnH z!BBF+vD=OSxuM1hv&w(4@SN*|!f+WiTxG1~Zl+=|@67yQI%n`!VRhvLCVquI`Z=ld z#&5`b?dId?(1l0!zS8=hlmsRp2uY&?L~F9;X^eSN{X+QwzeAly<_R ziCenG2!qT$)5_U(@5U!DS4`{8?)KKG6*eDWcUa62SiW!%E|0_#a+Ao}v9#8}^VkyU z-mAgg@^w>d)IE4FzSg3g@G_%d1FqHNwuu#vFP;C|2Zsk(*9FSK9!jwb6+yVy^V)qh(y7?O*+(!CTJ~Qk1`F= z)3K}s!v|UgMGM6vnJ_aqlA6>8r!Z%fxO(QvnjAq93jn z;A=G8%VFZc`O>Xs1>*4AVEjIFmuv}OotP$^6Kt}P#NRqT!Ah#Q0w%i=G2Yo!>b*ap z(xfYhH(fuFJQGMp z{?F14K9$93dy=4Q!WSphEaSb%pjNAE8E35zi5r=oJrY9z7CmB$EP@hUaUdKJme!n~ zfFC?;v8nc{QBNj6{}1H=_c-K+B_ob2gA%}q6<( z>kQwLPHVZeBg{l`bDy4#Jc0R$DTb}>cq;yjBqtQ&V6-tCG+P#UB?t<|AG#Je49i~J z*LAMRLD8{`lg~Fp-QZRwnmSG~w3oX5*F2Bluw)t$jFTaNOJ-(z2vHxo(*FICT8)8bnYP8bwus0@#b}o(E6ENbOtBuA5u%Kupb2<-Jw>0ZRC^19R)wsr~(Wv5?ep6vJ$&_*3?&r|84VU3O0Ou(AfYrR?j1L4ldwI}$Lx~n+6TlL+; z?HQED5m)+(3PCTf@IG*BRLF-z+(6upfT-s|4$8nPSoc-|q=Z?$b!BWe@BM{TJamH=5;pY8A>Lb*wiw;D33G@2Bvh2X%!?01MM97bFJED)Q&q_kU4*lw4;+&e@Vs|Zz5rcP1;Xdps_ zsh&U=i@qvgcl+Jo%!Ecstsk%?&Vll7KtieHeZmptj(C$e5Y2}MiZ;n5#uV*Qt_dr} zb8JgK##4VisvT0}Pu;~k)ZNfgu=C@QfqXb>H@w>5`_O|W_W@ZbFpXgLQ!8urtE$Sc zd+>Q`X<8EPut1kam5|*5EV?8%p;1*qh#ax>9w*^TI2c83iPqvK|FL)~%&y&4 ze=cX|CxCzLR*W#1uO>` z!~wq)$4P{h0e9TciIa%>zaOQ+DN5hbV$@*v7+?MinE3S5p@m!&46K{Hf2BmYJgnh0 zj39oeYKUfjGr(~ie^NEx1@oykr8r>a$t7w60#QMYT)-Vx#N0*gSQ+P%+2f~(wQ0?S zJj&kmJl>1d;nqG$<=xNV1hZum97;$GD%388hN~HrU=?r|@-GxVELW7;NR; z+CRPafm$Du5P13P^>M}dO*%{iF4M%s(C7vpRAX{pHe!jj>Jh%c6LlY5Wq@U(UzuTv z=I|I-$TY2wN<^pF1jQYYA2xY22y^Mxl(d>zJ7`@>736ab2&9o0DHr-4gyKC?g7{q7 zF6LHgl~4+4DLmm{QVYD9%`D5=Q?L_U5?(F1e^{=mX>HDg#l!c-*(PF_y&)v5HKg>~z-H{Zc(2>cY%K_FsgxI;?tBZLraS6Ro-XyyA9j#x>9nfNB^}aSE zc6#OZdn+5nmN!#`71o2@5Q^n}T{rDGet+lu22UWecTH;w0{Ooa63k5h^Z&pS3_=ac z#?GCl9}I#CP`sZjC}R)e{YCjcH)G106h2dYCrik&2}eK0fv>fZa=2Zb^Yu)C7r>cO zC>hWr`z|a*_JYjyG6Q@IOs2<2cY3f1i{t<8>2i0Z(={$t+o8X;#h8vXY}qw8iNvsU zaBP3aK+8F`eeTuLamc}&oE1JrYwy*%D^RB!Wj1vMi0*6M_&r5CA@`IfL)+-+*7mlC zvR=vcf{Pe`v}3SA_`#ma4FtNEMyI3EG5Gm@^_C=JaP<*t*064i__YzAJTaZ4fC+VX zarB;blW(sP^IJC*W~=WK2;mx2n5#QYq+|OM+T1MhP}%){xBb9@*oUF1Ynkx zNx*6CZTDz}wc?k_VC3Luy6sJ+YUd<>^-zx{M4qea2ONAi$eWcl=%+uTZgHHXBj$#= z2KhB{!?qC$E3>6pv2xyko0+4fIkjc0HO=2IV>5kRRoKDUYB=@Y)-vL-v-7ujRV5rn zfaw@M^hxW)h?&8r(;$}(0r<#dQ{AV6f{3%FRHe3pc`r%m_p57#tNP_62u{n1ku>t+ z(uK*m5N76~xMrFN3N`#%+_)~nlDl^slW&6#{WW869jObr>gP=%HN&Rm&CcQo zzHUfA0K6to|V2|p3biKz2$fHFb` zZ6UC4BRdVKM~!i|(SS#dsT!*jm3A+bF3-F)f6Zb*HiH7tBRG!b*@ULw5zN(cjqWms zNtH&MW>oAsN7jJ&ohH}Qe9kW#7ZUvBKpyRz6+l-v3mfX3nq;QlUqUXH8a;)?i%U!{ z9L!Xro}s@Ao*yA6e!1iXh@M*q0IzYYjIdj;l*LQ%_^K7BV2RZesX#x_Vz8$R3JIbbZuthK=@D$(ocFx}5GVsz`A?Hs%-UrMCA@ zS_&9^pf81$Wn}(r>Z@@F6dP$fg9e{3d2R<3FFLcV0MU1)M3GoQcCHq6@qUA#htUtS&Qce}Dq4OYl%J!NrTk|!_FCU-6cmZF^g zS+EsXT1>etG~8uCEPrt9LBreFseF*e5>kyY<83@L4Qh!fE^pf8QodM~ERa#GlyZjn zuWXHsgQ@xE3sD=@F#fJR5INBpcx{)OAF(YKI(<(5fh}l0BH{{QZx=R)4!0 zFlDMwiOZP=(`0^yzDK8iKK{*I+@UgKEfRlA8x2po63xPrHV%EXwimbY&x!GAG zE}k(3q;KN^x;A@>7Re&njGbr_25X}2pRR$v6m^rn*Y?GS#i1Kk2b=U~v9p^77*tE8 zUVYs*Ozc(CX+d56_DJB34lG0MtK2a?ZYJR3$|u@JpsIeaiThx*W_2cd8{Y|k?(r9u zQj{ZXu__XvP}7;pi3D_OPB;rs`W%FM@O1C=&6G+BLsugG1wRM}DkhZ8-FS$qqrz&Zzl%s&Dtc3Go#PJeq+4xeO+KGnFWbK1OK31$V#NZ|;q zu+23n>%mDe?cx2^@uF7RH3R+z=Z9;A(b&#r35E-^j{eV6?o z_(%7%puG3o#%pZK0O&?!0k`Q9v^_zUGH(O~+4hfk0KBL0kGUKSIi6{hu}WzPJ#J;z z>;N*%!G1DG0VZWnoH%S>F9duTZ)w%(ORic&Ua-kx@8^0B^L?*BwI zMiU+d^gU|0@S;jk+5DeYgKS-?(nh>LFUUpj8xlk3=Khx4G{7=!2uD9E6#(EH+!bL2 zPKr&4X1uM0xoJ3aY-1M_Llv{rPx;-|F4%}B_-|aR7x{0Lj*NYF$Z(hKIR0xeKKe#n zhE^n_c8#p<6Y_lIgN%#o*HUowFKRu5;l}sWn5d8W1{f6|!oTZc& z6-d266XpN?Ab{*fodJ+}NX=0h$sHW4TrYm%EG%vKt^0muxi(fm(gTYtd&BJK2@aVi z@0lTdh0wWXaQgxr&s)Zwe%U5)FA?G|bc$Z8u}m5(!EAom&G3Tw=Rlmw6NxAyb|+oq zckd6-@_#;qu=E2o(2})siqHSzY?VHnIb=_?aZYB-s2sr1^`3FgDo2E=M&w|(pfWyX zO*sGmljOU7evedLX`k4e#_+TJ-l4TwnH#k1PzX_rjODKdY<_H;fcfo7F;<=tadudX zdL_OUs}Ui`^n_F7E^eAZ#dP_*C8V{0VpQ`VUN!1WiKdYKaarQI|8ZHLAxif7vh)C@ z<Oq8ZPNJsts>o&dYGoGxcmdr|8rDMpaY?_K)Q+Ss#XwgOE&?LeZjU%9&f- z=2L8eU+G2>O{^ctNGBFAcSn{Hyz@AVDO~pdysdcb4UjLcX^sEA)F`F}KSpR^l;+YI z$gW?jyz%oGRn4d%Ql*7Z^FudVj3ENn#8+-!^`Cn@V6T*KRL^O{DOemT>>n?N^^8=k znofJ?yupxZ(RZYJQc+- z=UwH!?EqtDyXC3V4!@9awjo)+%tvqWH#XcgGC$~<-PLcST{IXoYk*jjSeyf-wJjU; zpfxhF*xUbp=xVS)9N20kD#lgPX8hpLm^m%RGP5i;P={#3WbaI~Y^+}*B^n=;a=qNX z=|4`FU0dQWim;l#Uk0g?L~x)}Boc0jXH5?9Fu)QP_k??1nu4VdSjyt-$BK_VXfdZh zekk8IXF!}sd;qzh_@M^d7A<~xNCkL4gZi)v zsRmzYd<2=+qpTdt{Keqbu>-PWk>x=WLT5W{P z0P>C0iuosM{*Ci&%_JPVpUGkT#5RUbKa->TPi)iu-?<4Ep`z8t5Ghy9%M8k5C*CjB zum0b#E_+65cZj0OjQ6(*q=rf}uH~PnZ`RD%6vF!5Oz90btd+rAfG5`_-#q%tC>-LT z59s%da=>wrJfzB%!mHj#i z7i@Q1#{E7SBA@zL%@)b^d(o?_f((~;9>W7EG!q;-@NY(B8!O>J8vUkn@{LU zfs_l_DKnW{zggWNX)OP-)WPycip02Ax~+5j5CUAI4MzuPvL&qzyYSk%6oJDQ+K2g(5cmnb*-DwqCFVNZ2Pax0=i190lm_jMN_Ph$Z%6ELLFz~uPQmFeyj!(*cOg3r`;>k41+ zOxH00dcHOh2}20x;`~-&g|X5icCg@>`{(TOprdb7kO#%~Mhl|a^)4(M&}!q@Nh2ej zNHionu!uqd=~yyUoJfKAm-g26lA}q%v1Qf4o?L5PQzcNsCol%UeZueFW51eM_Td5I zNr4v<`RUn*-O(PVp zMg4>f9G=~pvvL3aqOFF~J`k@eB$Wg9`G5@0_WAs?uxQ;wSMf`#K!5wlqGFu`i}aL1 zi$n79C1BO$rOl4Vit=SezR}Icj!ykH=8A_C51 z4F|UIOp0bH2LjJu>55oWkVF9wnrWx*(w7=(%01OEx9}LqPs)A$P_|&sA}s_MLxDp|MP22+743JGF~OnVj_s6tQ>cHSh1cHLOt0~A%|hof zhqjZ}HbRwEZr_OYsVV%k%|<1F3CnC#vog{uRG!!gezICAzhh@n(yH^glYIHQ=ht>0sVhn53Q{$)8RQTv*AG+(m3e$^?ULEh;k%5`qqL!G;v z^Vpav*^!!`%OeplmntPyX?1EH?zj&oZ3)tIo?JF$j~M`%q}AnK`i>_Ntc&WY5t%Famv zr<1}ZYI4eSAO`r(lnp-1WKVm5trEQ^>(_7oy}O9CB}Epzmo%0TdBk7WP3BVx#Z(0Vz=+{OY{7Eu?-Sqt zPr53L(Sj!E+iYy5os}YXuwzm4HgSII_;*W0-H68NRX7@HP!nuJ!$C&AcCX3l9tch< z_Mscd!=&sHM6t*HM9ok`uD12K=x({S_!Y5WxD~NA=vzBu&WPxZCfyJeD|&baBxooZ z&D@%f2C^gI8Usy0Ne#*z?A9=y7>IZ_uMGHUaeufZDYwy_HCZB@OcFYS4==mhhAm&U zwoU;E?Xbg9`m!Jsn!I}|B|7JCx`KTWjX2kG;bof3+{K8tv~l1?sOm5?oWZj;zucNe z2wgs;a{1vBXCYu`Jmp@qCA-L^b_)`lQu_(h(c;7rpsIVo2{N(B8UHo=gPD^sZuAKp z?6{)ucXcl-SNGrYX}bLFrhVW7Oa$ax#MlsIO3Rm#d;T@&^A3ed3Z0f=rs^iueVm0X zu$cEH`xt~oJ$uVk8QK73(YE86wlxYma}49Q@XL(#GJC}5l@lOtHr{WQl-fp~X~Nq2 zYuqrRnJfiBFhU;Bb$0I9lMP*utD#yTxhMh;sjn(E zo1N?NAbSS=MuS301YIL3WjuaRgosY1T6y~cLF9=2>n!}YtAALg1Zt!SludhlW)w{XBX4_AyGvGYz& zKD?MDVYj{%?$grDN*K~^WSJCS6}$q`T{j0GfMDColbW+zMKIPHQLr?fsy!OS?_r?- zJj)O?o6a#M={z+n1~;C|%x>=DNhV3XE7J+k6jWfQ2>Oh~N#b$~V}47kNbAvj7gIhU<`HYZF)lFtXn{HK9t7^Vy0 zZ@WXj@LHPUpZgz0Q1f>P#xl1pPA<)@j@|*f|5^M@5!iPPT#?f}!gw!OC#WSM(zk-1 zRUuZ*MEFBQ9e3^M*(s(3TM2A`E-*tVd@lNQy-;biT+1AG92Y7F9Ph^8$zrONbI+lHsONMJt-9QM+RgKCChhyPx=Zfq+NG=6XM1XUc&#P zd%6nLM4Et)L4SCnOKNyN1=C09N;0^GSinyD&`|z=Y`s%-AYB(N8oOiLwr$(Ctqwb= z7#-X0*d5#K*iJg^*w)GS-=}lNeW_6|HELn58nyP`b1wBQgmH!N;3Fp*5>6wakn5BW zFb$NKMqhr2B;H#KYRq#c|8<*jj05_4ul$miX8*0vky)*d5BK)qrTAAa^6BjORO$)N z+cAWTATUMA!7x`4J6ev$+t?Ca*1sOes{{@AkvUEw@aZSx@%Pr7l@?>HOiF3yL+H2P zDE1z@w}vxuS6gN)6|0e{k^CtDn?S&HVV{vRP^36#7$|i#pXuSu3@=F&A$7jF3Mj!? zBs&*J7}6ylm*)_SgTO{aScS4u#d`@R^8keJ-QDqcRL~Ey5RTZH1|K?s=MYlof&()K zP=tnmuZzKhcwj+lL2!eYp+9W^9h~$moIz$T!Rqo|3Gi-(4rp>Noo@gM2h{mWy#KnE zje(U#pL@G5BtQF-LOa_YQ=HU2M#-N#gVY_&y_nS&x0t}LyH`DJ>%NrGM%J?E%Wue{ z%f%!=h%7_-mF7p~6ZTz+cS;yE(<{~Hg#&LN`x6T;v9t?QdhvSDXKV|6dlVvFypou` zX(Y@^6?J;KZW-W)eS?88jOa~r--CODN#<@0vn??WHsb+Qy}zyd;Yj}c$+6rXU4kmn z9r`apW^wi8GTcX`Cn}L&+|G+wo14&#Mw4M@NqqH70FQXR`!*!D_>)M=9}gO-2Zm6!FP;li9=okaAQ{gnc8L6auEq@JkEren;x z_l*+v015%Ve2<#klmb_>;=?ayt~7t8mDR++$tu?Oy(cO% zSdrO{^jo{a016i2pG7UmCClNb&{?kVGI&B zEzy4zKZJjXvJoIz-5bhbSo`j^0J~3jWsO)pUyO$kpSb%;y9p_P_T$h>mMepG#ie*) z`FFKIQ-cFt{8b+1b(Moa;NWfZ{hRll=#!{pHvWJ#Y|si|1yRy;?Nyycn3(0bp|I!8 zNfXN5rF2eYuAhnAd&eu>^{1kw32}4f_EwY&Mk;sPWm>1r*n^(-3@f+ zxv&{i_^Kd);7XIV_!XguEadHBh4j5cnrs&fXEePX_KEU;*3&&wcU*NwXB^DWhpF5x zo;s;${F-Yio0s^Na4k^}^fs{$1P?H8{(8Q(iV7?7Vzm{w2UzKnpi)xN1K8t44s`lo z&GlSMy7Sp%WahPrbVY&>MGuWLN20EU-Fkbqs@fUQ`h$ZaUsh$ozNFjf^xRw@)r(+i z9hP;LImahXpY{>Wtr7155Spb8CJREeS~)c&OE29gYlrqOaf7a$91_TqZa0>@)UvUX4Ms zaQzIBtRhGi6e`Ak(?nlq40g4-^bN5 z)z+^eON=QE)bPqmHdCM4^5#A#j5uko9MCerK>GOly98<+~cMz*zy~@(mj^Fi6km%;g9-|O{ zxO`ZA^3P}(DW8iUI0LqN%23SFO=81M-bv>yIHPyXRlHXmeJyU_UrGbGpL?uhavw0z zoxPu+{YvDtX-!RFD*t~CCI`oVTZH&&oXub~06P!&|J7o4>B}VTHDh#7*Ur#bQjsBu z1b|pm@eE>=W+x-Ll$;H$d{O<*Fa>ni$T_0ao-e)OTbmYeBWK*oe?ov>fnQy9L57Ta zc?d;WeR`q1-fkQAc-_ZjS&*_tW^{FD$rOihI9jUGp{7h3GFdqlcD4Z-cBMs|9xBGN z5|`uI4JQhQ&vWa(E=jHb9Mqo0+qwX6Hl-wTTTL!j+SavA{|@W%&4;MW+S?QV9-3ya zaA@0~_w9!s58ZRN;Rlz`U)$p6aa=+@A5_t%jK!m>+lv?Pv`@A= zOHrM=m~!2NCNx6>s4&2TXplB}#KC2)(Hj&N%iF&EiFz4%4vvKcu2sX(AtYuQJLXzO z2I}~#j>g1=;af+N9sGh}-0Yk<(w81M{&cD`OfU-V_l8Gx_h1L)haV3_0fKWR1n^0# zYRCx4M1juzfeG!TE-!Nh>}d@~6ijAA)nMjB|@YK~bzNe{2EUY&IEw=nJ_@n80C>{E!Ck>D)( zJ!BmBg^r-;5;FplYMGFU-gY@U@+U0PbAu6b0zd4lXq|hG;ubfEJj$j>i0ov)prLUu z%-|s8MiOhWnbiDmB3b{Sc@L9&O73!F^-C>bwzUOj%C~`In5JJY-7KYD;|OR*IR&uw z=#t^McZB5nXpF_lT|(bi{KEI;Pw! z>!PRupgCXtjSJw%d93HhqG_3>aUDkcKSYl+=ip^8so#Z<12H@t_)X`hQR99s!Bv7) zUxAS8SN><3#($<&e3_Q%42ctJoKv8ITrfyeRuy7ljg{v%u1a8?^xSyjtX}|CQ6!+^ zvp8!obK43k2O6zmbBD!UEHjAmqU9w5gp70w4UCNj#^TJ?C%Z*A!p!B()YrDApq>Xt ze~1?y7A*@}@8DaoIyW;aXZ(nFwrIyb4PlLe=F-U!HD93V#V|(?at~wGVW{#5$c44& zj9NqDHbRPic<=4vFMwCXgKh&<2F%tGEsb(TCsN1pv_Q}=O zYvTA~MyDdL=hb1MlL$+Y1*BU=^`qTINrr>7s*t}hC+!P~qcFlN^11Ny0d`WIRZu@F zS{KerwE8;|s^V}|y<)rzf9sezLV}7^KHVrah@3eDX?8Gp#NqiF@u`tP)X}1#;*~n? zKO+d}6VsaS(_X}Y%1trB#n*B(c-mis*famF%Z&-Q@c1PA@7AmzQ z2FgF4`3ao;J9!9}-8PWO)r6F|*vA4f%{E!xZuu3g(6?+8g--^eD2o4x@Rqvm1#chy zOP7yN?F}KQHx#siHne{;Dc<7 zL#BT3St(TCD@Um1JY^4gY$LZx?)coEpg=UMXVFBq(qmDjrTTXS555W>Yfg<>BBy_Ur#6jw^bt}ADra4} zWoFpK+=o_;=7!SFT(I{2J)DQod+pU6LG)p76 zaD;vLrm)8Dy(D0gB_V|PQQwj?L;Y^Y6xE&XQ8|$Io@@4tctsEOtl`Xj*Yb7OILTXp zc&p*eUC&T+6&%n61bMG}93P}UKwefo8b)HnTF5x}0|==n?M8OrzL_)hU8T>YS3|>k z5@VU=I1_(`$%FVS^wA#}=IjKg;_*x=qj%nwqQ0P7Ba-ILpX**LczxiFKE_K|l)5F`pmFNB;aJ(6mfPbn{ZEplQ^5GWNdg1u8SKy`p zD76!Abb4RrEHKQ{QPt+yuy;$z^xWmnuckPK!Scg@w6bJk8UNOFm2{i&kHyv#6c@~H zp+)`S=>ySCZFhp0BPA!4W8p6^EqkL`2d_qz`XNHjZIb{bPV9OZ6K;E$P;}?D?YK>E z8K$XeAf=f&-2Ux@9}%R*9q$uS$graHr6k&!)286E4vUdi2>nlOA5y?V=D?OU!sC7& z*M_l%{m*aBUUCC;6|O$h6q}WwD+w2i0PPRYq)cj~%cxAb@4mA{@cuuGKLTo>_l71S!g8SsxEVD2)43mXe@DaJiq-)NMcU;^I@@CS9+@w=U6J8zdW=Y zPqYHLSqW~Z1k?QnhV=-so7W6(i2BrsKqlI~<7A9xcP|hPp7`2cEk^_qsD3={ZIJe; zXP-{ONmx}B*5h(id3)S!-&!uwa9e%tDM1_U~)Z3Jo5&G*@}C>tBux9F=d^vj;g~p7?Z*YknOZ4 z`EFzd^G(pC!;ag}hVt6JMpv~nd>`R(wo#=Oj*@x1rT_1P6F%|4e>JugO zGOSBr6W+h#)ywy|m&l7ER}VY_9rNG)zb)?53j3$KArOtfd2E7Sw$Z+F9dIC>s(tte z+X8>Kx_BQ#vz9&{uEpLPf3!d`)*Bx!Tce=b@fWbf`I2TM@nk zc>a+oBA9kN!-T`$J-fJXiv*5QeyrxG(=;mdKij7&UEi;5?jHg%t~wmc8fFk7b-Ww{ zj&a3D`tbJo)%oJDhOw4?E!l=>jGU}Du70SAro9jL9sFJsXvE<9NOe!pT5pDqaz}J5 z6y#+1RrMXF-^BLXFa?_v3lN0vs6xA7J^a=Yv@Dma=vwGJrU}Z-E5fgCPLz+JKt$oo z4#6h22F-KOd=aFHXq2WuQ~CGppH_Y0@Wa9RzYf+{gpE=C}vAMUpZ8f$j(rWc|Zm|kx~U;Jtm_syD^3j zs(;Qx(ja#qHQmf~xkZGp&Y#<6uFe+e92?bVTkVLT3X!u_fd6^>1Q+MDf=gQ-`fB{x zm|6Z`wkjv<|JV5G41YC#tgM{>cjKpL7x&fpy$kmAuOP)hjaf@vlh8=$+6R+czknp> za0+vY&PoSR*so9d_%2brGE3rcw&vzaw}PxH<~a39>JF}JsvhM%ofp3VRQ>6s;2m;08osV zm`qmanuCdFE$2~3Sz%o!yWdspt7s#c2&f7cH~zX4cC7)&t6?r-OYePshrNSlz}Y+b z1C8wYk{9D1@-aWgP|_0>`(xZtSc*~GYR1S~NS$RqkEX{v?UPc8_sWrqhR;Il?Agi4hH1NYL;y4ZDif8}htKGa+jl&B0p zTd)x?$XVJPBVOrv!OfGWX^i}Tg6^o8%VjCa+L*Nz-F6HsE7M&zSSXl$so|-#Mt1UL znhDCLO?U=YK%PHu>Jmv>0X=8)@eITFkd9h;zd9mzy`=+nRS*jPw9fAd3I^Gk;`_aU z>|X4B<#>0mG)eDl&%kZr^#J~#HP2F~P^>(db|jM-o)3r>nnFD^(JQ;eApWy0FFh{p zA}8qw-vNm#6#M0OQ{qypY?!75|0?~WDA2(iZ!0qblPx#bsEngRpeUCCYi8E9N-7=t zNYH^a-TVysp4NXD1sM!ilH!Ontv(A9nRI^E;;{auly2e`4Q?pM`FcWfPX{}}MfL63a`zo@K3`Iv4 z6MeS@rW?rratC~HKzE-m;r6aEM4`R!yI z8efP0A*b;zRl!nzK}A)OmYA@DN20YC@~EC)SxmLZ%HyS-Ey;q)YXp*8MD6F_72eg0 z&~(L~AA+U&X2ve_(Y{z1X5>q3_=v*2&qJ`1q(C$gcXuE*^M=B{ei<1iYsRW6xXX;v zw2kLGeb~zkrYOp*ESdUlR&V=!l#3R!XNMJn&p6jIk)RQdixw>F&@A4+k7Mzzb?o7k zgbxKn(Np2)z}Z+%=73hbzEy3hDr4TZAukP=;Q%OpBREhSzx9M+YRmXWVQ!tL&3U&_cA$hd#iLireHH3)XHACe`SqD{51Ice zQ_7~VGNt`0(?9iuf1AYVm4E(rxd2ACcW?IyZtGi~n4WTMWgG1y3K?$iv04){4KL(g z1tyDF!2E-HOZte8*x#3`J6~s|_}cu=?mr#{D_)18$b#b_5Ut~Mk?F@!aa|JQDO9b$ zJ%b;3CLi%~eA$+k{2`lYx=>;9PpxWpu-hzTQ>;~QH$z(L%$dJ>NV8R+3+US9KDDHo z+l!-B51DSAkcp$cQnRv1CW7}aaH^HEmh0)#lza{3u85BF^YMcllb4Lz`jM3%paV^%G@Xnu?eZj|zH7$bI*%#vw)rm#jbr zS+9=`FBK$IA!lh9Wl;HgQ<3=+_dkUL;8D_A>XL6fE4$Idua?smZ3Itz-JvA=%}v#Y zhc@$T{XZoX7B$AVn}KJ+UcOr14GCC83GM)fH)C+FnhCAT;4S1k*#~%+(8m(pEiu(@NKZ zUeKp!p;eak214&EpFdfH{bcI~f1BGR>7is5HkOok@+!&UA_E_Nlnks>8bZ*bs3^Jq zl^xZj;^CmdaAZQU=XPB)BhU<_3tMczk{`M)zp2TU4>R|P~Q&tNi_G`Sbg#}$pi}4drc;^_wF`Hv}GK_@d9hleG^37&4>OEqHae<3P^4#nd*nigYN+RN8!N@Z^lfxD+U8gg zpM@oSdRL%nPxD_bZDyw?|MqS*3x|iCQ5FlAl#h$l_o8?tyAjT<$^8MZ#zv1r-pc=mt&R+Xj1&s0o zVZhX0suLyrPXRZBzxuP$KPNc(Cc-3@h3Ht}q?0)f%F>rR`00Ke*TA>Vh^q8{Ng3ti z>Xip-*jxpC`-2fYDb(Oz>L}4C)A3zedtCMp5xsuSZ=<7iTeeC+O>yg^*oS)^tWFd& zkG4hTXmLD3*yW@9f290$7i2i2+ee(PVsQXC3PpM-NrN$s9;9TZuhLY@Y4)=+2Rdh= z%b*F@VulVen~P0<$N)s=+ywLdWH1iV+yHdN%F4~}s<0~_v4Y=Jp!86bLdc-E9HcA5 zjYBa$-etGT67F^BNEYo=BNb}DJzc&J7Jv}(1~?k-dY}+{Tdxz#4NffQ0aFxyPqBdN z6(V!Uj}_B=Fq%Y)3FA?OJ~qN?d2jp0>=kUg9`4asA z_LJ;{^C&Yk;DuZAFf?#g*06X}bNw5RE zbQ+9wup1c(1&lN-Y9TSP0ja@UM2NGc@8_lOHqWyARMY92|K;t5QrEQK=kQdOT`!$e zcw=Y8G<6a^B} ztd5g{847+ulr-SPQBgP^8JV0G7BvYS83YavM*0m>ypTLl*4VR^KsgGjELL227Q{p1 zR}>c91;~K$>DxWbet z_e;wFh)vuzNKw9URUa&3AnD8sGFJ!zI^>`xG;WyS9* z{%MgHyNt9J8p4d~jg1I5D5%4D#@D)aej4W)DCsk7VC`2#IX**>FrEp>d#CABQHFWg z>U#R5em9m_PC$5xVsAd$RNMEYA@91sSEW@&!B)%7``yf4+l0<@a4E6GI(9-QPZ6#saw@ z#K<#Ld!K=A3EEshcUqZBEy$7~V#LE3)s z(!U<-UTgXSknX*fBFXLrDCZ?j%i$qi-zMGUKv6(p9^mgj4_|BJKVuGs8s75cKRu;r z9TgRO-tc=sKL?OJ!uY)3MU2Z&!}`XB;Uh7?cej<%{yCl7ik$B_PJKQA6(+sfJfmdz zb;*a2u(z-GaTdtm~mR1KqQEtuy)3phyYNJ zH#!|IY+6Smd^X`P>_ZN~U45S=K3jT55poCs_Cs3>lvnzDU;-IlmY>rG3zU_pA((l> zLZm~vmqOTq+Qib^9RtGn?(U?QP4#%s{9at5`C@+iTZ%1WHZ$2Gb&DGY>7liH1--s| zpQVkbz-d*6c{!%PPMz|!c8K!LN+XOte`Cp?@aG$%QMh*YGsyuuW?9Ulc4s%7Lg_VF z^K<-mgq29Y%Oy8Oa<7d7Y84bUB!?wOhg#aPnP0!sn74FiM%dRLa2ccURktS%onyZl z`kLZo6uw7Gh_&BCAYZD;ux`&U^NGEr{#8)VZ}*wGVbsG8Q`f0TGn9FfEWVZ}ob~po ze?4SlCDPMym5>F%tMx7YY=vu04NdnDn+|wRzp0HxOKXD}CuO!$T&~)ZAmGHil9JD% z(B~!!^rK!}t&AxC(3B9$Z*t-9bV@(*x_R;4PMn{7=v&6esp_t~N%Z@ax;*$+h_7ZO zJmLK;@0xG6-{v&d%1;c&6^ExGLNk}EV*vSDUR{tVdG!|`C(9+0pvy%%rOkE@B zg1u^fjIeO17QCWKpEx#Ag6r+G)|tAm-xtnUv1=6HjT!tUUJ-h(ZRCIYV>Lt@TSRkM z;f;h{Vel~}#*anI6Jd-2vUYJ=u9DJSZXh`1;a0B2DQw9L$yAlF3DM(WMBCn93C)R= zjXyCCxw#h5hb4EKp#4Wwa$GdEmA4e}yLAMUu}VIFRo%^M&whc#!HtJ}KQ{f}IUnmQ zmV2oz{xrQ zhy{U+TFTPzO;A(inhT^%yadnE9;-tCOfz+Txnm5Ivh7U$S6c!J-%^DgF{iBjt-=}o zD?Via!E8j+!Pj)Z89;qQYcy{4BtbuMp$kkGI$EwP_U&oVPd8*k@HE6q1cz*`Zf&ul zN}6sI!x{Y3!eFA^OJ`nE8b2Vj3TEete$nuYO^kBu~a#?h5% z7VAi%P^`+SzsT#iSzHs0meu^1u&ueWgSQwEPeb1*mK;`2XKjtLW9Os!IH$xx^K|HF zQDFDU0}-ln%IMy+A6EGkfRsa*L0!O7FRdlB9W?PZQx|gI{ixgdknBbkJ2*%-6SP`r zQu*1ig%vBo->4I~EBA-sbkl0b7m=su4fklFvUfL7sk&dxPU7hmyj8!MW%&#WpSc29 zSaq60Ozk+t$7iLuQi6~Qhaig-l{chVUH(O|9Wts~>#E?YSA;ng}u=V-QM_zpo>5yh?-M)ssYF^%n!(xP$w@5P#~)k?kL0T$x01ql(Pfly0X4Vkij zPImifvD|OQp~Q33d^z+FM%q7=ZeIEXt{frU+WX>V>dnl=&%f#JYb~+U(yeI#kZj0K zHp@SY$*u9^eA%?hr~~<^;oGT;gU0g$7k*pn`Go~++Arq-ScUn*(1So z$@lQ1(x0rPXDx@E6v^=?cwLRjrCqzbevMb7-pmC-h?@%&yjCa0$ChDP72usbFmtfOtZcequrvNzJ(-0deT~n4S zw-u8xdAbuT9}6s{s&wk5`pr191dCIK2NS;?-;G0uV8cvXCMy(R-;gMy0a4u40P+_}7o5$Z=Vo4ux6=E`1u=2DK zmGCNx?sDmYxqLmcTSjqRlaa6(Nxi3l%BjoMgz@_E?7upkCBYJ&Pvo=7X`)AWe_@{g zD%TYD3R~v}Ek0$jsktSL2L5V4D(1jF?fg#+HU8hnXt0V!b`ub6lMy}sKvVlApDWga zprRES8sQ`~YT9sC$QVsUxMOc8g*J}6i6xM<}fh0NxX<>O-O*=Bi!zuVG1S(47B%NfQF^j7s0X&qZ$ zoao69cSuUG2>>(|jE1{H>ORtYESdZA1GwDPu?hEt_a}L&lfjmkPWsV{a&`2+o^2RY zF9zOya@$!lK&RLln+DjXN~9LMQX%t!E3}AnOXStmPV%q4@0(sqw-efeFLBpYaPYMi zYdPyM=(8^dt^RqF%L8#F>O*Y_zudk{PL}&vnYkuQm;*M`*Xr5bS46y2+l4da=o!Pc zc4n9O)UvG%e%w9BWtqO^i`5LNWxSiZE?4GBHa1+V9D^sFN-@+u6C*q^Aw@%c}|bvN8Oo5S8;7;GBu69fP+?{sEMo`CTEA4u7KL-kCnyjB__vIqFKnn-g! zf6Cr{M>ach{Dinr^BPR^+rj#l)Qf(j6NK6C!ym0XV<}1D&7(9pt&#Vc0KFgU!ldsy z9NJjx`~pu2mDVPHpPs{WFD#dlD}`IaWb?muxn9O1rka`|Jb^KqwN14^RRMDaV_6FsSSwDLC2aV-IS->o9yEUKjJ}lj$PhUGP`0|BzZc{iz z{bmsc!IE5-lUaBra-De8z&j4y3^MJhlqGyOXFL))GsYVk_}k}`p>-Kw zC{?xAF4a86x%(ff!YTt`t4-CG`3^k60j&*3CKScv zzeL}(6Nbd8dGEoshu>&#hS(*!azW<@xaa64-_`n852NS$-4<+OVMefFUpJcly-YPb z$7W^@*8>UKEZu1lcn3Q$(%md@_{N?y+MZe+Yw#Xkcx2{I+zNlu7BktNJSZxS$N;%_ z^IN9hKS}6Gy~GAC?>Qe;Oh*mGd!*@8+j5>z{K+^d9#iPj=}ioZRll- zMyneKp3hHc#iw!jJGWG8lw#=x@CA-$-qaNm-D1$IJhAGW#{00k61?!Pe_$K1Z{I4y ziNsa;*XtFPVd3MRC#ZT=c2z`90S{3l9imOrgtrtYvCS3;P>jxTa3nUot(wE8cEt$? z`p^De{qEa8Vc0_?$vv9;geR^q+;||rpOQlQx&RnTZK-HC zkMus>hL3L$`K!r8yVLJteN=W@wAwnI`mByHmC0p@pq9VCiPL#kxc766RSJvOsPJ;u+s*Y( zvWgtlGDqNR$+6M%uYaxVdkC;nK*UH*`3g?kTji-(mZB3y7{Rx7oW5?xJ{<*@y2#}t zmFQ2C`RpIlL~D7u&O1%mBOiFeU9iYfF6}O!v=IE)o9SyjIawsf*wfs7?0XJrGtztK zFL2i)XqIdHvZkE*lTf7c@?y4EK1n?RAF-=vEGzu7i+|_#)wln~Qi6am)8?T8s-G`; zfP89d(e@g!LR$-CHP|KBje+@{?~f@8boF&pA?Ei0#|A&eKt`_J@^LMXPnsK* zfVHRDIISH=t`ym`6-LvqD%Q>Cgidp}T&X|D4 ztg&R*$1{A~g9=)o(%|7ENRx7&oAj{0jA8xbbA7jmfgsKqs04Bilfhf|&g33l=3mI- z@JvEpw*|uUZw1HO2J&GIVuTBc;S%8yMba=tFPmPyl?Fflk$(rah%}@h?_OvR%x~0I z)U(@#3myU#CEb_9D_hSvx%m{6}ZZU`p{_!I{j^ez*v)y|o~|6rdh31FI-MFwRo zuZFmjtZP`==ECE6CD+|ryE8)Uyo7ZIYM|2pvhY$IEvc{%YN(Q-Rof6PryP;uo`6I1cuuR@DeUBxQXa#!}c%eMy zzUex^c}>ckgiijB)WP4;+vu5wo$|1Z%T6Lk5fezsnD-9I%2ciIXAKKM=3ZC|R5BFK zrpZt|{T#MuZ5Cb=QgPAXTJeeD*P^C}Iqpj{GQtFC$({NV&vw#Rpy2Z}+`RZwRO`6C z_A{Unv80fnlN>Ro!hZft;emweiP-K6^z840Kl(HkvkeE6_PsbZ*f+r3bUjpSemcX$ zPP>ZTARYu7U^S_3)~>Q^dT@F&PDHuQv|pke?awFITTF5%u*5Lp1c=5yjAu29XT}Cq z9`0}aD_F|n-BW!PF6s1Sqx%Lsm1dXx)5KQ@=H{M9O>tD3!m`b#{?(aYAR8bAKDn|c~BBOLU#Gkw4kU@NG&&U-(hv=@oq z(SgSz%C{B;lm0o*|HfXRq9?RW*Vr(lD!T#*K4HWgz3P{Uz5HlBI{XED>GecO=cCa! z{6hs&!2(C*`rDJiBZ1hvAtX^A7xz#*qtVq!)4nK?2Wl>E(}m1s`;p&z+lhO7j5lgh z(}BRl8`L&|q2$GajmIvEh6=aU)UwUe3_m_*9sHbmE5C2923sFFLLSRMVo8U*p5L#) zXp!~N>M0+RXsP(TQb+k4X(9RDjN4pNYQ=cCQoq7-O#4L58CMT@&XCH8YBO)esy;Tj7GS# z)^t-1kpU6QaU}k&=-h-OiO^bFYj*0u;~)4{DLpTo;*fjJXeg&h6n3V>>l0l^Jbj2c?`4M8OYB!3cJK1Xx097!FQ3;S#A@4+AOj*`!GeKA0_4hS@dkB zuDQE9{EAP%Tp{i-YLF7}l%H^l%0Iw6{XUwqc69`rHpYsI)NY6FyYS}uOWbwkT4-_g zGQh0q!rxk39SUUGK*5Yi?X-K^)H0nh2t9W(cc&k-WO#v zg9#p&g_lH8Q?2_|y!35Qqb%G2vmuffCfcq|e_Dl(G*940`pKY}QkDLMqBY`lbZ`D! zihb)>B}_`ImZOYZo-8sdr|+f=<*AP(k@0gm*1Ab`wkQ1J*c?O1o`h_a)!BIjF|tgDi>JY(cdG2OM7 zrF^UPQ3Bn$>fX3UJvga2fWTK~yCF43gnky4n?Vpcw1vxJDni=g8ki_4(!ME{td~Re z%T`n4_kNA3{Rn;JrrrdHOd8R757GP~*K{nz^%n=N^zUem)l#Ovf=ClaNvHHchiM7j z$J(y*`P;=sa;B!Vi1}>L?TLm*Mf0GBDkf7gJl<;pyko6VO#Out$s6fX4m;qf5x>RSn;KP)c_lVz@`WF_i9z(L}pA9<~L6aZP9DG)E zEM>taSub5EirGlHz&SjYk|AQv#p}fI2wR}X{lq<}sz*Q14+*uyGf=;2w9EGZ?u6tC z#V8vqj=L#CRI|hP?U`J;_1!JOsJ#%!Vy$d`E6VXU%v5?UB&`jvr_n+plVnM+4!$&o zm`>2hk~_aPtu5Q(?WjoG&E0LMy85vmDT}jL_PFYDNxd61VD<2VE@yOn@z$C2F*S(^ z3(D_1yWk!4d}oBq)W4h`9x?(y=A2(#dQ1yGJM$q31Hegxp7``TC&XV6yIaMhv$ zD6e(Ld-^rJ0NwpV%|Q}{{&rguXia>(Cq~=j&w_>{2@it5V|L@ZI{Y|hkm}J3*?~qB zXPp9=2BD=jyL|goN+8Eisx78*$p%Rg>tq>U*B%XALzjMnVV2P+*iy!UHH;PhI}0{Cx!8V2IsNsMm49C zb)Ua>P1Who7ro8BxMqKGdG*sxb&FtHu&B|y6J{(>amMdiqs(apxyxa@^YoBU9BNfIcTE|#;0A+X|MNBEv@P9 zmn9}yORW9xrJ4hf157tWPWX?t2XUyNjQRc>T|m4u<$_n}iC(E&P_{aD}Fr zG(L5saJF1n>z;sz&xbEfFg0KaRyO8;OtB z)q;nizTMrKSE-#>yjC*l&vTg#$pHeAvnnSIIBw#7a7UMpcKJe!iX%U30Ol}nYF!Oh z&|GkZ&-bBX=Psc1$Ml2IoF()l{&%_H4{Z{Tatj<)ekJ@fGQ4A}hBiZK1!i9^cCQ*rWYRG}#z*hu z+|f^V>Kw%I!P1W^Y_g;Zghye9IKn2?L(vy7={Hj-yCtvi1;^ghPmREr&}Zz4YpsBi zpc(Tnd4usIGp2!%6L92khR0HClkGy%Wl)pU9sV3sl{oSeZ}~0J^81oIQ;+}mId{>B zOGw=i-;)e+#Gvh@N7VZEo(D!}3S+KR={;g!Yz&dyRXwbhc8&8ZK*}wx*BJuHLO{a> ze-gHkpw3ua!}&dPDfx)(5qxK+pNYpvJ{ZW0 zFrlw;rpge{T#dn(_#dB|<%IbNc3)@dO9N(zB5?Gjx#o5OpQd2-m14;Mr5N^xcQU#z zz#`ql)_Ki|;buO}1~~3-BpT=2_=s44^x|J?8$JhZ!5~CBOaA>qLbzu74At`3y18?G zF_xt`xsKhngt-9kAQ1Z~i%I|Cx*5`O^=D+pOC#^l-2r#AKb^!Va0z{JuZ7qREdz+= zFed$SP9dbQNcM`07#-WTjgDDcM)*zDL&I<{@w zHafQP?fZVt`{Vh}`M0kt>#9`EIp&;IYt0%19$bdGPaJL3sCF=&p>Bm#$(4;%CA7zz z4#=u0N!LAe`)zz#^OHM!X~j=k~T%Q2~WFgF1}vjFns{o70>CpTw6z0DU!ao>aRc0nR>;&!b+ zv?s)bsXyKd{})?ztUckXUvk085c~cT%F7bai=03&Isz9;Ejg=1GKRo2Hq65>>#_v^ zPc~Uv=z7ReK%<}%M=6-X4E&KYs(8FQmqM39hyKC#!5ipXmp8@8Y&D(6B&IP7n)mc! zTH!x+1)s9{hW@=sAVXLZy~0uUY6FDJQhK>-9}4^vh~&)zR|=hK)~w0V(9)0Rb(x(K zt0%CYiGg6Yu70%|kWS%~*vSaqL=6Bvrj*ls8s)En3tZB6jO4GVb+ZVF8+E@rt+?d-VHY+(XT&9XD%~kWH>I_pD)6E0Y=&0ug14}FkGhSJd=Dy4YP-g}A ztf0%ETR~Mvfz7!%fO(PqjjlBqzLLjhrq@K2Ca17S`DggKQa8Umm%ae|gv)`?U3 z$uH@OC&^uOR4=w)`Sz;a{BMiCrrQJV8fY`1$1Z6oym;ytKJpO|PyKjJ(7d{4S} zE~qPlrSJ&_3yw{X*lV9z28_65_!8?072#P!I8~gS)KDnWV zq3jQYGLF=&lJVrfQ0`RCcj=k?kyv2wqnN8*UP@37nRjOf{1*nmW#0wo7c303o`eOk z|E#62QN&s8A~O$E$+F`=1^`+PFwwxMFYr}nm{WaF>*tJwCpl!Ht20(r+N*Y+6L9Y9 z=EH6sN&8+!@eBH$Ew7kBx$ZkkdhQK7Qs!X477jsw^&RftIf|}IcXWhtB1Og0CYm)B zdOZLER|EuHMFS9UNy;vXbTVSPnmmsc&gNXavB)QG3x@nS9@ z5|e=|00giL2$J(#6noxFKXE#K&k!3ncx2|a=<$9`l5w%UrAQ4Uj%KbvM?v$V9kr1*)|1U(sb8T z8Yvw%ZQ(?RkG7D4>L&ERbN-=8)@~ylN1s1TSJwC8;p2^+eP_4p8}5F>ZUHWO{jLbw z$A@uEN`AmB%k59%QAD%_tZ%?^5`nct=r1sy5`nd2)&c4}aGcx*h8qIpQDKdrx(--f zo}}Cm!DimEoEM~g-y80JBLIRZg%S@9r!GrlucQ1uZb|uq+!{W3l<=aBGrlYY-_S96 zWb_5??=!61&37fx^>sHZ-FL(q7$YYI-k$~mO*|WRP0cqu88n{=1f>y@>T17E4H)=% za$61)gG9tLq6GOVA>Jpo_T*FQl8B9pZHzohhR&z-sr zu0Sx%s|KC$hy;w@axvCkXW)LU)6z%g#9)Ex87M7xL!D^yY*d;U8Eg)_o$q~yPVQa; zgp&~U4{HJ``o0!#yz~H*GWT8k{;an%fh!Xi`^fr9KU(iQ%iV`vXP}zO)-I8i68k?P zZi^7mT-6>Qt{IkG;K#?}@Qyo&POx@mOkZ80D(GPqDMM%sfH zmFZQeFS~a#z`tdPz5@t(|GatjHY{&e@-C%Y5Pe9TobK&Hz_GZ0hVC(3QTugTk7R`0SNgDj)+cq?s#_R4 z5$wmG`HfHgx!Zt%Em(67XjeuW#Fa%eHA;v=eU=CDR9SsYa`4-`*Ol zzDqL3FQ^krGD#-vU0rCF26J{WMC1V%qv=!iia^PqN7=p^L7#3Q=LB^>TuEX>3*ghP zBZ^hA$E}Ei{Ph~iXdP#W?ICWdS0iuLr-^DquQ5wT(wWlyuzT7&N!Ldc0Nr5jSZau1 zo$dP2$%A6_4v$(xZ~cFqBf0)PM}jgZFvC(|{vVg(m|6Z+Ouz@_{^wvx31DGkVgIj_ zWu>-k>^{f0uBYm2J2SG$YjT+}JC@beL1V@YD?@)iB1^q*H`Q7xEhpzp zwu(sc8zsWC-q^%QpZe|V$?nS*z~{BY(`KlTN==_sy{E?-Op&JfZL~Big<6~EAC7La z{XBxEr@2(X!MM7)bZe65tq4Y*5nm!{GRygI%4F;Em~6XaJY*gJ{`!Nvisch;wI1G>Y$}1d6(KR?2*4fldggd z#ZMnj*DgBu2q54Ix9yyh_-15H`pLxS{O;}Zv_}pAH*Ct@n@9!pv|hwYt6B?h_FZ{> zRnE>;=gQXoO;6fs2feFHqj%FKbtQeZXY|sL{K2b>O@n!)qIz9#akq%nq_d8>=@XjS z$A#&pxJUG+>F=hYDy&Fs=9kuN5>u+e;9H=-m8Ao-m1QV5(bTxy-F~qvvZucsv^RWr z#W^bg6wRU9nT_u*tQX{*3(<>8nh0^L>Yg2RyS<0nZ{#f_nYBL|Go^M7!zwtwPKUND zxPwLH-k}#*RcR8>OcQ3b(HMbi8c`$AJZ#f(7X% zpiaDNi)FJA+b6|E>|K!PSLzf&s>o+0QfI{j`A;nRgD;dBw34?t{u=tC#N#>^yvzq! z`DT1<)9taJVc@VriQ$Y!h{QkK+nh;*hIzI@6$UM)kJ`efNf5b?9q@z+{nc{JD-0(x zhJmezGet^F)Tc`83{k}=a;}9c{GDl)mmKE_p)4xc@C6rVHP)a-f{7|tQ$Dpo69#Dk zpziiVe`hZa@soR@30bT$Ze74iB?+)HbUG6<4@tWRQ_?4H)EObG!5xX?YmZ-a8S*Im znNMa%^v6LUGp$DY%Q9z0@^KBsA6CPU9wI@!DQJ?dT_U8pKqkCBMK_;jC#L#t7cRH- z8i5HsxXmW91^#CQn9kT?u+8EXua#e6@U zK*J9bkJO$nU%GEC>bx3FbPK7RI6}^?*3>NdIK8xb{s688sv^^XYne*v0QE{<_r-hz zX0kNV5!(T6(#WuHOqu&6*Xok+Y~R^A=|mj_NsJRZ1QJy%6m51hh6i;M3}ea+U_jZ1 zAp|}F%~- z_<>JP`hV?7x$~Y5IK!*rtiys&SAyVr`~=1QGDPBQ2D9F2<)*Q%t`(KvXlW?Ir_Btqjc!2g*8X%UGWOo`EERV#XOrtA((X% z$7wd2&BPl%T2rA4r#h{b zbEs<+ew4SW#8mt_!GaS3yW}nx$RzF*MRpTWNVXVZdNmKIrte((^sLAzCOEIMDQC*B z{3GP4MCGRs^-!0>QbORj`8tH81XE@}<{&qc!c}m;bR0bFRnhKd$Ux6GP1sjF0JoBG zc~g&-9EJA*`0+^c2L*P*^AGL%d`7XVy;_0uQH+0+(fRo7r44T`pf?g3nh~7m%op3r zcKLN}en%A$JU2Z?&ZkuKi$*~XWrbZ>d^wDR6zhe1y7Qo-&@7&hAz@Q9n5XC9bksuo zhWdN#cbW;(vnBO~dl(6DP?VTtyDL_v1JO8vmQ+#6S9j&t!SNfn8x+0uj)A!|Y|IuA z%PB=F=&O=VZ0)i5y537;|0_4#bK_k3kTtX993y4`TUT^NGIu$>crVqAWre%he8=-t ziG|3emjxEs-z$@P-^=!6CxZYr=#+eg1VWyUXg|;A`YUQt1%F2#?TW4z5C;U$uOWBe z`(=t64J|d-_NNELhYh2*E0u>TYGxNr+Zc2wNNc?(42)@pzUDedoF@{*8x0Rll2z?zRx?~VRLG6bXb8wV3=y`f3x8}`|D|n=fqP6AF)$4ADeya@bJ#Z@ zsi%;#+0OUZvLhv?)`7hBKwf|u->(FKAoOo&)3=os(oP?q_-P@$G+0p?P>Y(Ve>|HQmR-`qenU7zaaqDv-%Yd zD<@6entt34!%&4b!%*@z!;(Ho-imbAS0S}aq*UqYUw+lL+Z}P-J0Cs`dG;gQRJzx#sb6E+>xyOsr48YPhjo#3{gWATX-24GY z17-SWLx%y%`tNsv|9eLV{2Ne|8;pgynP>+L#T<- z`LAtWma1%Q1{08DLE{-_ZLrrc>ThlAeO{S$(MB6T*N!PYP9}Rz`^QrwP6By`RAre| zTFFOrcN(!cbYgyN`F#@ErJy)OJl`<+epoX4U1DCF9)E>{zFJ`_3+5?0jVu$@wE6L? zb4K2i`9uGQz5yU-;)xR8uX%mZt6wRYHkr9$le7;$6E(sz-e`(@jpM|kK`C^0jBE6c zZ)|%2wn+S5F9Vd%9NDQQN7>SJm|@C;?T`8+N}FuteK|KwdB~gkqR81c%1PFxeEgsA z@M)5p>WdWk5c3x!Z(;Q#Q*E^`Y4uO{I!q8OQ?nqWy+{BN1e!def0io~;vf>`D6pn07+;%oS--@Z&2R9n8K?+_b zw#sY&-5!v>ANBZ3un-B>&8h%tANJ8DZ_>eKz4D<$P@#qNCE7DI zc*5_bfAOEPF$9i~(!LD_2MXkI1b!O(ze51{+3epCVE^Y-1EhKUZ?ca`9XtDjCe+Vt zgW3-Y@LCe(LNUE~5ZIXp>bNFhM087M$OFCAaxV?1!p(MPz^~(IFP+P^u6Brzy&?&8 zZv3fnR#6_U&FbHagxyjHPwg3uU9Vddv}St?re3bj&B|7|$7wod9I>v}8k`x6-TC)` zQ*COyf}9vL=cKX|#ji{%71xi&^$bD4L#GagWBgx)ZUyya?Lm3k&)aG_SJ$j`HtVbB zry7jDH`5KVB@xx@}T}a5Ks_q>o=~4wo25zV3ge?!w#tFZ? zT@inACLuWMJT6l3Ayq-7Y0xlK(6#>ryaryW5u7&pGpqTyW@+JV?(qCD&c|&Tz`XNI z6s4Vhl3SOq23cPyidXPpJJ3$65@dRC)Tj#9=fEr8BsklYuq4hF_Q>#3Ay6EX#+)Pr znRd4uM%;q7bXn}G$Y^UN7;j&0?Xsy2PcvB%*wLoH3JX;Hv-k(mJSIQr zX)s0eTfbwc(D8g6!%*+F%q?WnZMw&wXvSTFTk>Sf!wb+8WlZKk$%C9GTO?12NSv)+>5_f{52;f`Ch* z#rR!v;B@RubH|Ckv9J)KW;DPvt?}iqzf6&qd;UtbMSX)RvhX>+#2fGlzWCVF% z$qOS4`Y5W}W6Cv;=%m{L!}j1&-P=ty`8J3oe9UzD`P6wc6cI(0#7}$x-oxygm3+4}R`So@ii zGQAi7e8g^o&eL!klzoy;cWx`*CNc1MHZAzM61b5>dK$t{k%fkrNTed106>GL`P8&Jzm=U>;i8=z#r`84 zyd(6C(J4HpCxnaX=jQ83ua${&!Rzz>E$ZqHMLU4M+mE*fRIAq;fx`dB8IAXh;YaT8 zl|RB#z6Z(_AgpUncUOTjw|5JA!xP$|P`CYABbc?I?NliPV`g_B6gq!U%d8cx;J)K{ z1&41bqok*z0Ngw*wSBy%?UB}Rdt6v3$u^l`dXC753{$9U2A01cFoa3g(06&ruEvBq z(VSW|(F=ooa2@FR!9ag0+c9;(GxfRS6E(!{u2Lv+kO>LMJH|%`>OG_O}IMF-? zjp^a%c=OvUb&h7Hos{dWT7GywggWw+w)Bgv7bfH*M7F)F*9~(YQeJ> zQ+g2UY|rQiSfxGpR_jSN8*DEFJI@N|i2J8(9oGU(0WJr@d(^UD^kj(OajzL#LoA+< zW&3Lv1%N8}fcp-DgIL`$9WslsJ>nrGWh*Cz9jx&2#!JKTv(`k}AZasBj70l1?uK8m zVx4~<^u)vGVEd^>KzGxK7bv%(`gix3Zw)C`ZsAzh>yaPQu-7Rc#NMGZL>C!}bwJk` zB0d25wu8?ILhD}IrpJ*7tz1l{wovgWrm?wFA7GF|r66*NVjIL#EvhM#!P4uGY!OH4*t{$9+6z{(XRI1jZB_{@j1yL! zs+c<$e=_+d&r~Y-q{V~H<-A!7xa&DHze_7T-u)w)=c=Kd^KaBeMzVE*Wa;7`(`O*^- zppd^;HYrZjPrW_K=+QLnUd`$?#1bkvuk!;M|MvUh2lIwVW`w_bU1^oM5 z4~A-AIJ1Iz6ja4^Ee0=!?wqnuP5_l8=j?SFMG?~`YaBUeVA;njXgo{Bd!}3<_^3ny zVlsK6bIOHc>q@#THhk(5sgz;xnHYFmgmo33I>IRB@?rd~Q0~rO+{Zh1jR8GJDE*uB zRYiev0mm3aXS82W1B@l)B+^Ckd@G>9TY;Z!(|y56hQ82?f&aC|*)sLwIAU7XeuW%fm3!1&&HAluMWaTq!)!@uXzc+dS@L;BU=LF|}ZWqfxvmysbuN$Ig`ATAjr1ET`o2 zrQtEgrw}-8j0XD>$xq~ZRf^|rlsFjNs!o^P__REr>OLuZiGU0nL;{$+g&#J)CTxUT ziPIrR20{AwXCNuR9pVEPLdQ8%f8Q4Gc(d@IjtKh5?@$~=V9#L~B=jMPT59C6209Kq zX4lW&@TmBiVM#HflY+XC4T_6qs}oUg&f;LXI2dHWO?TWH>+kk+y24OlcxDz)FR==? z+GY((JJ!ZQTLah$1bk(5LG(DW;61tK>mZsnYrZ?j2&HBqUZ=sWVf8gpi?A1Kq!ccW z+a|Le;&bkZMeF?BS7xiGSqK$Rm>wwqtTrvc29*-VG?wVPo(13_W#5g)yZn4%q3cnl zPQRe_hP#lgZYJEJc82J7em6G<#y~oVmdzAk5k})>w>vp; zhs*bWE}+lTy>e$}p$i{?ZVk7B92o@YI_J+hXJ&S|d<8<1mZZ3w>XXGY`QpF}1Q?*8 zDD#W$MgwjU^?F6uMt@$YR!ptA;gj^w1Q`3Z}50{A59P-AGxYO>+nGC9MHDG1uSz7l^4bNKwcUdem$Ji zfl&uc)~xRFYYSfP)t#rbRH3pM6LvVxFg)kU!gAYBZ2}I>p0`>5ItN|~ z0Ev0R9xE>8`8|A{gHM|z-Ic1Xilb!4es&+4!T1Sne8{i)pEH-iH;Df^bN#0s@&961 zWM%>Cw&8=Z{M(=i{Eo!J#PnY;7!GmtfCP&-AHKn}lsNonV#*|?<0@eHYv^*w!W@V* z`tT!lwrBFmKCdg2N6YRZtiOvIJKU<)F~tpjIC0@49qa5H*6Kh+Zg<0ZydPaIX1FWW zpyXAH&||r;2P=+ot}(cn`jqAmZkpe4GU`?Vg5u(zOcGMs4`tFu-Zsb&m0_zV1tCZ# zPD6T-J=;sP+NUj@D#}gjWY@~{KR+&G?YCCN&xf_GJLokl3a=~CU8a}E)&79xX0hAp zCpB0^jQs_bY2pU%)cTrT$np;T>{dF^=LW(}T+B$WI{x z!194)lGcknI}V7vTxMK#>s1vpOTkbq$<`O&>>@~=e&A|#PN(#hw-tMk4M0Pfvq2BZ zY}i?8S+sXp-8kuT6FAnn1(jEA%)I*ISowI>G1P?!EhY~IL6u;0&C{C4Jh(3B|4h_K z8cAoFTVK)|V)Bw*TXa<~))Ia5fWMRnVEYYAXnPU{P(52&iN;cMy=dsw<{b+3KJe2* z65EN3Da5+X@Y{cZIK2ermqna24Fj~3_d5Gcz7QJv-^3X5a;~D&= z=i_aAS5AkE)V6E_5^NK36NB&M#7(psT{aUqQFp;Fi1oNyD^G2667dKJNH=H!J(GJ( znF5D8JF-J3+RoH>_?18%ac=iSX(uPu5u?~3lk-$0x+Px$ ztv~+`pB;R0e=WB8d}}|`P4HMe zJNMSneLaaf)J>B;7P=!MP4R_ zH)MdQ62d`g2BAQ@i&!*~Axb;KY8`hWD=|m+8A>xt(aXW|fye$VC@S5u!8N66wYXU= zENz%W@Sr=c#X>WPvJxH;fg1r<0jB_Zs%i1WO@^%f;rZ|@#f-e1HaJQM&h=%*h*w+S zP;=t%CCRFV*1is&GshF;@g1s?)WX&G_Q{@0tuo9d4gUD*8$~*=^#Q{t+=o19;{8kM zh8CcHt|#R{SdAYXQ4JgeQ8iyT&#lS2eYL<7K6vl$EG<11f+i9mvxG^AV(*+UnWzT5 zp2K`T%LvOzowmsnMK^a*)jssVVu2R-Ted^I?9f(M*_{DRegHvu1|E!~D-!qMDxZjM z8`Sx9YCcO!{xx??601zzi{>FeXP8cVO(64Ba0k)jXJR93ej;WIB+U3J<8gk2FHwOn zp`A}i#BC*xg8&*JK+95)V{Fg&Bs32+{Ml#%43$+CWSmZd%b-`K@n&l;*NW-m8Uyr& z0X2#tVJ)^IdxOJR}i`Ki^8H1d|_0T7*1xG$q5NRerHW7rl44OS%y2(h+O}&#xT0# z3F(Y~hE$g;(bw(yXKMIDVnHYfGnoMuY5ATiq`!a{?AyBV$5ir})y5Ag%Qqd46`i z_QjcEj99o@Ztd1E_Z?(E*Fx zU+sAN82)p5L>OjCnZF22KcAEGFRY|<{F(0DVMXvT3*TRkRAz?@S?-PdxwW?V!|PVV zxA^lLa8F?4O(>*W!tXlj zR|VP?N5TUp<#9OjaDyhAN8i4HcbAUBy9Ib~#pQeSr>G#H;-T*B7AHkgadCl&BSDOK z_R#_<_%lU+j3)Pb3d&G3CGBT7<9t?!)GX0R9&eQ%Al<8!Y9?YRWSG8*;Z*C!`so+o z`L;76t*69?J|C}6&G6!3ZlOcSs?1!o4W%B;1n|oWNUcLEHxg~?V;$JL@fS%#nc{~V zj)G8shEGC66c8_b{f(4=s-S6zkYV->d z;a%ulvd2GH8e&ej$Z$VfT3{S_h@~i7F6|v}#@OFUg|kKqM|7;Wr{728_wF9GB4BcS zMJGk?i#Dd;m+zlo8&|{~7!bvLZvlHDim}q0%Bn({;CU`3Dk~|%9lb<7^O8_pMnthg zl*`3fS(G}E*(?i6)QSd_m;5?B#HVtBH?ogr+`@00o8L z|7>{Vwf|?s^FM7ftp9&5X=b+n_mSn_z8NY27boX`ZFd%R|HCKU)!nyUCd{IHL#!-A zC}Zs{1`qR(5mVQCt(OMj14@5vb&E_Y`lt+T|2HG`vkSZqqJ-2^ z)oQYYQmw_o)5}Q!a@WdtMRz_4*&y8f&Nps-yPZAv^3+i}z0Q(C9UmwojdDWJSE&#p z=nzU36igxku=u{pJvtajjG-4)lqA^VAcWD-v2VqoK27XA;IWm)Gd153Y{fL>0?e$M z_AlyGt_qA1fA(~rx~RK>mFWZ^gu-t>;tud3!X#oQf66$9ATl=wgU*zLS&G;eYPqhy}e{e=jTJm*PUTFp)!X)NL6QL#U0XoQAXoO4|sadiDj$(4$_3 zg?W=0e?)|7Yj!pq8wh|ZI}{aw!yd%+g_zFC9CZQ&t1~OQ=4{YaTp-h2I*wwN9fam0 zk3UUge@ah0ksWal+C&7hIh$R9;`CIP{MfV%OjFOt^291J5SFcE69FLMJSmPnf~5;80U?1S&{v48)N;Vb1ENq;P4>=Ep5= zLdOtUHS?&=yS9GoH~IHm(eIVS@x+Z3hxbOpyD@#qeOJ^QDlIsLrF1jA&ykgLecRLO zS=G~q?fzdspzAuJVJ+T(rf&k8KJ@}qGEA8@*IHJheCif_M?E|QOyq2!&c;eCr| z1kgwwyMam`{;Qg33``6g##k`5@g*0Kwhj1an%fzy3B`V9xpDH>U(QfQ z-=^l+R9U@&>L?RK=|mGP4w0~E#-s+LST#V-=>4EkHcSSiF|Nt?Xs@g}B#*9K060u* zOqTj3bp@3Vfh9Roq6a5W{eGhk9N>E>X)?1fgPh0is=ZW83|!LR@kEJ?02u>pj&8IY z@&>#IW!mY2=q7;O!H+Q25a^J4BngMCm%v!qlMPwri=P#{--Qg8mGD#RiY_!9BhvNT z2{TZeXdGzj>omt*OkO!4b`}{8fyzYAOA@;7yc|C$^9_n33)(fxF~hIXmz{YRVO#OI zX45el2`q^Va-Y)yd$BF@SzX#CZuOHtr?>?U<6yZ>Wmxg4Cneq>ua}C+I~3ZW)CG~x zQJ=7TW0>(y8w{dkn-=Ir&gYq5z#d`!c={=$@|Ocoh|_HJPJ10Hzn{2V+`o+!W~%L_ znkCv`{e99geNPM=2o9A)O;8DhsF z*qZ_*W&&vB6@#7JeMNVNw@F#4H5MdK>hAsfezUOh308$!9m;?Tz}hZA6YZ|Ci^3J~+M2cJxdse?4g(`#00qzUR=4LL88kE{DXt>MyWfomIXiWjjQRzasc)z3r$KF5n}u@BFc%Bn zCdU_6(tbxAAHy8oN}A7qAC;b13M{M$-d`IdR19VR6at0dvf1!#`VxQ+I+q4I=)C(s z!DYMPpyzl^c!~ZFu$ob!qVl1sxHX3m5;bIa_U} zef|v+tbd}NmrvhPo+aV`-e^+BKK3})v^=6!Z4SqL$m(pSU1DTtMCOiap)WJf*8&g< zJ%G--0ZtH|5a_HyptGzz|Ap};X}mUbcGl~y;>7c9+$+ZL8{74mrS63NY2qO#xHw1u)f0;~A4GG{CO_$^QQ`YMYY0e)vs2=Znisx?q+$0Vi!_4lI=B zz)1(e*2V)#^necnmi`WEml`kq0(CtVMa4xoOAk>B36W3tN=^4lN*BOoW|&OxOBQ*< zAe6yvc$_ASgp@w;qKl~(w7f~smK7w47hxt94F>9F9X|leivB-kWf|yb-TxHyG;p^c zSk!@(EtPX&o5<({-kb1m;b}chINoJ|+VU@jhGKvL^3rP#)z5B<7Q%t`%kLl^le3u# z1(sf&LMq6~;Kzc^^SvcoCsR=NF6(I#TlR@93wWEp($|)P7S|F_9h}%?STj_?91OrH zLj#(@q3@qGXcQLRu@6KsP{#QRJERk3ls$omx12LT=Vp{E5cOb4Wa05|3IZ<#LLk8Cm?|+rC?}2ldlPXw$}3n~UdJ z0w}0PZU&tS+$VkLg$9qEUe)?3X<-zAJ!Xf=!cI0V5Dg^2p|)1XcCYkfO8oK>dW=pi zqf^c$Wf_5O%hkBc_I&Y4RX1aA2K{?oWKSBd4xXj5hw4?%?OVs@GDl-OnloYS-ABv% zK6?#y&EmxuwQ7UFf~yhdQG-Ty^|$Ybi+P6X-AQ}1&CdqePe;xJ)Ll#IPvk*hE}*58Ygw3n#Gq3LC<% z<*h89&2!SQ++PsjEVuC=cVxi>EU&9{c2~k#+L60?Ul5d|fMZ!&nJms~*>h(a|IsV# zv(uDo0MNNVJx+X|6JN7}apxOZgQ<0yK8YzOvDalQk+pIGa=AC|9$`N*6$J={71iX+ z^QAt5yl?Iv)&F{6KG!v!P1(mA;0pEVYlj)QLj=4tidHPv-MHnV7YZRCsy1c!UV6sEnPM9K63Jb>e6#wzn@js8!D}Ox7oRD zr>L2kG{4|p`9PeruU*6|3B-&pH2)F#rWVGg5KvnY+&hdu65ULw3(8o=!NI+lcn*}g zjD+Pd)8m>9v{8_EhV#}0T-xS8f?DsU8o;6j8jMcG2oCCA+@3bJ=E*V=VY>68C*ZDk zV3$}eudv~e51SQD9Cd~%p^=FHIQ>x|hw_x{1YNtPf7VDCn;Dgu#P4#89lJ)rR~7lF zc!m3hPUE=c27Q@a%i0S|>+l>!VLuKvp0iD|Xt0=dc_uHlsfB(Eh_VB@|LsSI$iuIH zPJ^r8fS56I1`3MB}VYz|%0-%ifu%n~ipOX<;D zUuJ0P%|Cs}a~kF2;RxnfOS~YKl;_Y}&qzIi(vjIweOj5Pf9Khbc0c&}s8hl-80tpE zGn1-5xn*~~*_iXPrsr+YguE%R1#npR1AHwaZ)Y#1&0&)SI55`iIVeG&bF#dk8$lPtsiI2slx@u8~N8s zxqc1v9dS5Z#_bd`^LmWtM!74n9D}LRmmmBLl2$$PUyzbBcX0pvE(`0wt&iwntjzzf z@#}vd%m1VCg!j)g|2BScGym7Ad{b8|c7Ny}nuOkGa{Tj%%Y@MH&|#qVbx_|1Zn%7F zvLGe*CT5o6>d6{I1K*z(W(%dl=cEdwKs=2&GbT@~POHn>BgkQ|w$Qe6s)J~|J6d1w z)y~O>|t( zQU)IsI1K==V-&x<<{*rW4Vm)U&Q}RFDgEQ5*Q-6H@QOQsz*lVmRakzKWbo)XR#La> znvJ_^&zf8`U)e@| z0<8DHiUx+BmT7M5-8Co6QkLOKF(P3M-Y?ZAlin&u%Fu@k*LBW69mPas{t68njdMGw z8&#KA|E${5m$t;rzIQR*4IY4xM*NZJF+N;Q==*I8j==XKT!^yvDZ5R;iwC9W_w~|N zv&Qx{81m3Os+2YkNs%$ZeQ8_M9AnOPI$*26@X5k35r(9kkr^Buf0%?|Vuy(d0p+SN zkoJe{pGKGo2T%>IHmDg(^7kjtyPn2(?N>+*6^2tvs5use3=#XC=DSkd zo)+`Xjt;TGxk!8D>?O>51O@tg5hGy6)d-9ayo6j`~Q6=;LR;Ct2Ze=S0x2{-= zTU$z@XjH;G?$X&MC!O6L=PSDcL1qgE&YzN-sI4^}Fc|(DU!G;HYI+7|b|G4B=5fORR5aiAXXmRSeRw z^=P7>j0491dG#Nu=0usG0L0#8+*O8zfKu}8{yl#+T&*nn`2IUbF;5Xm^;cVMlRKv~ zcGD`o43*V0b=#PzHuiSED8SK7-&47_uCEEvd+mTD9 z^wavNry!ka{yXFfiP49k2xu|HgrW!@vhLO2^!dhOn|bds{_UBEs^vS;YGhkdmI%x8 zAXqYiv?+1)w;aM|5eR$QKrSSUK5to5fsW~7SBNdqBZ_|Sm?$18eSnaJvt<^jeI&Hv zhhVU~@N#0+8TU0*HRY^xo`7OD?Op;T@J4(Zj39Lu+|?@xtPzT-%Dy!Y1{0I}+FQb4HuS98 z6I6}EqtCp~(II?1{xCr1(TZP;--%nG3}1a{g=HY?#@vg82Y5`Db7wkwxokz-YKnVc zcz_C4zr6Xw&rE+3xskj&QO1^`CKPl`imOw3KCRx(dSk7hYk*W$*}#39860tq#b}#J z!r5bXlArwu8>ItQ)q=N(5oh*Me~$-J{BACgC79T>pDRYp zvPeH?d<;ox!e{Y82HspcF9%EYN_^wcm|}X_>|h}Y&rdgPFdJ6+!y zu^bT9vCHIIRhj4E+%e{2Eel~xUaBa0{2W*%d$3Y9hyo@H>d9r^|q9~CGX9ytd@k6N%_8n=Thwm z&vF)7D=vXSFHA}#451K8Y+wc>V$4uvK;9$UMk1)6DTb?(K}+T@p-ct60vA=w-$k|l zcTv3pfU63n^B=2<)aeIYocLX^Msv>j)yNm--~2UhCQzt>3M~&Cq%7qiQvR9J7%sLC zG7iu@Vm_e3>Rk@g!T1WXxfjSsz82Q@xzMQm4=wo*|^r<>gNDZ(0P64i(5bEeVMgp}E)?)aPgVKb$TS{Y$3##SJWgqa}i3(r|E)kf82E0a7Gaw;aQ|r!N;sA5{ z(dPyv`cWijRZO$wC>;j_(Z9yHVo60P{)v+6!aojB1d(S5;K{bq_7*<`KeW-20%13` zV>3J)DgCw&4`gkw3bb${bY9*+&Rd^OX_sj@D0wh>$AYr$T6hb3X;Iur){G9}X;%_sHpp&o-NVZdb?}hX`TcYViOEABoSvuIh z5&h$Ko!Hg+tMAfa!VObT)oyU%7TpySsZya;&P4!6C(*cMLnq@DU(efZzx7`Xk$eV@ zqVRrxo%HlC&-3P4NZpG~IZlt=Sj^k|(JMHqKH=Qf<5k~Q_0yxvdEsRIddXIqcW^slOV=kzm7#8$a!Uqy3nN2Mmlo)G9imv2zgSm8utHL2g!y6+J39^o3z>YZ~Ny&pp?Mde40| zGvoyTav)Z~fqD4S$D%pa>oZ$^kul;iF0QB?a?ESivOGKW>z$m=+2;Zp%FOynJplp$ zSI@~w5Wm)NcLfc*1*MqAjvG(9>ruk3X5LRN zfV3X9kMOr>ieT$-$J>|%7fvcf&}tcrKDl9XuYR@_nbU)1yYo4+`0O95R(SCQI37vb!{bjB5B4lSoA#l%|1hv$t|@q@GESm1>1Fc)JkA|) zVm`J%{byaacz;{t&Xyatj(&gB`xx8&#A+eB&Z;j;A+QF6Y|%*~!iI@gNn)@AYY%Rt!mLovncE&giCt1zlRq z&i3>%2D+!6wsj>%Dfj0?xKa0KulJjhfiUK3Kfl`xcu+AIoZTsV{f^L3h>!5JX)2A` z@ye!JxqBPOM=<(C8RM*#vurjB&`+9-Gp^aG$M7p9d(aA~1#R81g4I{486 zp*k|kwW9;!4ijv@m(A>`#LuI6n`EIiO2B!Ah>=Ip`D$kiYLOB7e= z8I5zq!KE~fs=4+T5KMjt^=sfa#?IQ9@7(yqEgRYIwgcF$u+=@YWn`s&x*5cH%5?!7UjytW4l<)hB z>t7ehs)hHs#7h~lI&AjGL_Iky11REMrHOZoeQyW&&gO$lKv%Lmz3zu(-5eDm0x3%Mdy%mMsypR5uWQx+;2Q(km)3xR%miiuAz>;hjPBhW05?d4$F2r~r9ZNwq9c z2*#;ufd}u7R9T<1k{De@iNE!)e(L>@%C7f*C%@&RCelY|yy4V&-czcn%O9o82(dW# zBw7KKYnkT}wSvP^p99}J=~0=~Bl&~+7t`OX1Jk_`A36FWOw7AQkuT4hSeOa4LV z<{XQ#eF(uB@~J>CkM#M+&^J(W$XVP16YBNnAY~>ED?I5`B#KNHpf91A)2y5J1s#{_ z?E~3_`4)GWM?D5jIYvyTZdp74>L!WddXFnY=clFM8D7q&iO~{nXuGW$1hn1q7uDiw z4j=C^S9r}8IcRwqNFK~-l7omYcp_uR{KqexnO^zCT{k8dPiVLA)uloJrkbQR@T zU;adF2iENWUa}_2U9S{&y1Z#xHk_0Tm0*x`(GvO8TDE{SCYE3Q)gvR0dUh z$2H8RA1vesYLb9ugVjy}xYhY3Fjn4Ta1;p!9ZGKARUPq$M-5Ls;U0DuPw)4JNj&Q6 zI6M{Uq-y_8@!f-(U0XD>hcDG!k40P`6WAfHS+`I1>-&5fMyWiJWAniw@S?hMG_+1F z%x?!+ZBkiM^26~Ed5Ijy6>_A#GwkOOcJ*4_g>SQ|v&)|`V>gwZfIqeZ zS4!6jNrSURVkgAYB0nyFKr&lFLx5ONt6Psvq?`!aK$e_pj6ANBWbI6Jj{edg*4gW+ zwd?Ya1gDv%%er6f===KH%31DC;)?cwZ!L;4VbgGS2YrA~pJThWgics*iH1g`(@DLQO%q3V}0q%^zOUY{)&O^JzM_tqR5w{OXB-%{KmTMo*%rP8O` zm<)^4WC{SeVt^a@UR6 zj_qyqEv$2>5idvRr-=B3GQm|&TSGbYhRzw@P=EGA&a{1&{g4!(E4i!!bZ0sYaPxIW zGfJ!)b5#_?zRbL%YKFRY2&7v33h%eKFnWxfwNdynYfub=t_oH+wY2jrXw}X&5Tf=H zx0>(B$OF*s2Wx-nSMeyiCkJ-wIO^7GibnELCyC8;Sr(&CoS0__T2i_Mk*DbIp(;|= zX)gQ!VYi1yBRRpLe%F|GM$~dwO>);g`Kn!t=5roYweo3n2E~7rqi}OP#(j*~facM6 z@^#}ukrb`wECg(%tX7xfS4b7|ds1yV$4LZP6PI4>l9)L|TGg zROT5X$^;`azxsBxdHsd-J)dye=TZ#xMx?kW^yVfCJ`^5CDt|%2yXDW9pq}!8bC|D+ zW`U3vxf4#!<@T-N?!P+c)a^S}>TKv*Z(U0h*vU{ZpEK`7YvKhP%C6$!Hj_+^MK{T( z{5=2DlVZWI5E#9c_Z zZ&?0XTurM0#r2)e&|Eol4;k90vfUhmmg_FfRKo!nq36C#_>@j+IMMUQyLZ2xlEK_x zJo8i7yPc8BGgmj+!7sc{gHM~1&zuK<8ro0619~8T_NJ&ItMwViOQ1nEizbD?pf_fdzyKZ2x#U>UEod8LB+H zCSW}20mc&u9AG>F0mc*T3oyR)7}tRbbB7m{>$d#5>mf7}v>8pI~d*3mC`HwDq{m+=eaarPEeU&z=jl%1jBjR+l zsPm7+t4VAZ_pYM$TjYzuHjmAmzC1oGrsRdl;@UdWSDR)4v_@kiA; z09zdeX#-o5k(LWkl8`S;?1fsaepLh6){U-2{-G#hj`NcY40q8#h}{Ml=|T{LGsb@b zBVA?7kCd0HT`xD|+lg`MC{?4{YW=BJ{DS})`#?QW@nYE3$%Gu2au&cJ z(?Fa>Eeo-zywNMB8DA%EK}~~%`@|@U#a+@I{Fy-CL&aTbByT_br7q>BpzIg-*;PBY zXwKhWoV&!;eX$~>6M|}ix@xSZbWAh{jMZL12}F^BvHBP&0Y%3@B#0f4#}aF;s~2l6 z1PqntDj_fbA3^;C_e(iO5W+nUp)?Puq)8S@576EaFf+>SmOzqumr8UZu}B^nl?R;9 z9q`4^KM+rEQfq210KVO?-jdn(P*e()wx#uFB7LoY5z7(~u^f5<5sTkH5DR&X_v~Oe zAb$MgY}3*Heg9bVjhN^$C_fy()ZpUy|{nFZTCYz^ZqkK@S- z>aq$&ZQMrAm!OTT$LZqDEb^d)FQ491yeLzfSF}Ots7H> z$*7?(nz2T?Po!n&HFh%62u%(Ls<1+*0WkD%2ose>iVu$Yzi-B-_Q4VR!?rSkp%XoI z$L&Jl=m+Yp!E^=smtY*^6|KX6fuwC1nkJ}Te@PXfO^+`+k7fu)t{B?Qgg;#{ZxzDe z3q8wI)vdJD(w-d4|Ap z`RezKhZhbG#lxou8du+PZ#!$|Jq1l$a{u>HhFP za!NK9wtsei0FL=rv-JO7n>(m$3(P4|Km5A;Wc)?pO>uA3RRXXqBlY8ati42jP<_d* zZ)_i3na!p+y41Prb~l$k9i;CLX9|F%NFXD23PBFtkK6RPZ;8;{>WJ8Qt+Chledg0M zV_@&A+!Uy6Nn~I>89feyEz`8;svs_?1GKfLs7P+8`h#Ms4?<`BS)ZSJHrZT=juvaF z>}q>`o^Y?>QR~f%= zh=@oM49k>T+<%tZT7`~su!HzDa&-ih=*TG5qG4phZ2h~`R)_ekC~Xs0B&K=Te-$e0 z_@tutaP{EDnlAGyLvHZQn?YR4H)lgcYOHny4o8R!JlwcUq%z7eOPl>ycl!}*td7s1 zvXM!2^t-Xi)XxF0gjB%Vz_3hZeXSRgji3yJig@ZP&hd( zDyEcyGDP+|48#P)BJ@;5HlZNAm){+&On$yFSxeKzG|VKa-sy3aZ-GBK#hnBij{{WP zwZAjxVz@s$rrk{s?2Pi)2mE7T&Cr-Xc@P*F#Sh3^i^}sJ-ade&#|2~buozu-RKRjf zwg+3`%fL-s1hrWC6fdMV|8L%MHylCdsLv_LDCj{PbUt+ilAWk-;2yD8(#L4-6Bgr@ zy!lt$m>Nu%F!+8z;@E$ z_?cz&*)b711y*JkK`+4*JVnwVr`euQK`Y;rq!T*M!OI}pHDFV92WyUBTuPAA{%?{x zc2dPYStt+C^wPW=KWRnGa|gQ`hnV#Sfh~Dl(4qz$3u4-_c8a;otNwxFgX?Vz*pwME zZCm%6n`9gd>sblg#GTdOKC5lB>5-8vT z=jC43)?<+9(a;+<$;k2C>v=*IR#GY;xUTwa+|FH?xuV=ssCf|_9UAc9i|B1;n{RN% zV;fiCYEkb))BFuT0D-JGHt3uC!B%+vyP{UMSG@7 zSX7!nxM#5sTwY{l477}=u_a2r_h6`jcgYALsJXfdFZKDV^X+5J-~A?1@7MwyVY*F~ zu3d`+HiVMSZ|+Z<WDlk^~2P&!3{wMgF_H2Mh3=9(%FF00{_mq7o&8Nj>3i z(&D>uU?pW&Vl^wleWK*RITHuG3S8+2{Gh!v5Z+@yFj}d8;p>u|vNa}b8R|m&d|9QM zR3k+*4{`J3QVll@m+=YtUL9{348_|kPGb~Ts$di-65W&v$_3Zd`6hZZ#aZd2O+X>{ za;0#CaF}08fT-JUW2mQTdt|w}S}28MuCPhEWxH6s2_9N0GfVRalvD>mrqs#kW|rY@ zrssd6Br7hwUKA0PqmlX8IZAvYL+!ebHA#EK6|qz}}P-w760zhB?C6 zv3_=_SYQ$ZuJm_8%c&5?z`JvbWh?gpLAx^<~HzXVoyDN-PL^QE8#W|AHs2P5Liql3?SXO%bl zCJ46L>qc416*A!%Eow?m&nj7V&-rM<90|1vLJV6#6?=Ya9y)dzo>|0buy3vlTH5kg z*_l^!|0HyO$B=Pi7y=JV>#_+4sNwf-_F1!O1=b9ytX|)LbZ@KxwDax440A1iVL(05 z>$l6|rpjGMW@XvJH6d)_3vbM+l{Q#o`gvJ9wo^k}9w|Ou|EgK!VX^UlDBHB>evsSY z&kAz6C&+ql4;hKaQ4xaR0L5`y`f1zDlN!hYdll-lhSfuyb$z@xiluW@HDzW&eo-2R z(w_j4z&+Tuj!`uQu(80rh>WHrN1vVZF}(0AQ5-DvW;(MT3#`NyeK=O=vy%`<)f?pj<7$m=XX?D zDc9F}_1^VEJc4htkHq1JQ-0sV7nm7}t z2lRwXoENq`2qa(Z31o$+$JMM^zQ!&7I9If0L8@B3W~pLKe~mw#R-aj27lBXtHrD}g6h%uIIxi(r^#&` zQ8esInlr~H2v3$W!WEL!&ziIltv_u9@+Zu<34*K><=HiP^Qh?>&^z(feE^`g0En{V`#9T%< zW3yT4>T}ScmwDEO&h-mZQhc|on$LJGc=xYb#)&nMPIp_cwM58-5ym&?z64Y#E73+uSwtIchM=yh*n?}y zQ3cpZ>H&T@EH3@(z}#GLXrznDah2`GMHW0G@P}wesTt<^)u(V?;{T9L2}z&fBy-Wa{XIzbE6mC!vmcKk!*_K76yjPX>_&>)Lk^;8$0~q_ zHtS5JrSKZ6b6w^xTlf0-H6$ha+EF};9NlW*AcL4fW`;$5g?G%O$hmglBl#F@~xM|E1iD;faL} zi!8g=f)~0%eyCn#jSmd=aQ$9unAe?TU1bvTWaM@qi%%!UHNe?%91U>k0Y0f`2sjci zPlFLeBk&J$zWiQ^o|ysHoa#)%8_T-SqL45%{)xLenFa@FTs3iDa7105YZJTSV%2$}SBT^T7 zV_HahEr`!+q_au8ow1k_iMJh`0EWK7{mz6|L zxWD4Wis2{E^vnc^7N`*B3~`1QCR)_1N zQH~Hl|G0Vd0~)zvUh8;m3fKTRJzuQ*P^GWaue~bwtoy)slB;0@UFIKG{<@sCpF*kX zJa@;tIx59ytNKD&h_gO+UFcCNP`XN7L*A1Z68c%IdBN>h#3uHR2C3zxzw zSQ2)v$b=s67$&bmuO(ShS4A#?KxzFiP%lmNAg4#G02;hrFmr1Nv= zt$cARk;lk96vsBa%vi?ar=M#$k^-S)43*7 zXVbkBpHjB%KL6uhFz>eYboJ0yygTft)&uDhb$-Q8%%i_K^#MVm@m}nOq|$qQMyS9J z6H(-NrJnBYXG+_RArb^O5=?f-r#cA_4UlEZk{W-(;2jm%Yj1ad8rtM19KHwD)ygpu9o6bu ziA(3AI3SN~NYA%vg+6q5`gm2SgZNaik+ryDF;QjT_Sx->e(mt=W0vN{rR7>Ei}AO; zVJquhJ2nl(Zp)Y62@3S(u20Y<#&P@qCB6I??-u(%8(jdK3;vJvlAVR)U+Lw)xVX4D zdH-9HX`}AO-}DmD-QD-a!1QkXI%EEzj4_?e*K%e*0!%?w#M;{3^+vWm!PWiwieF5{ zpvh(|0UjJnM!A3IdUyw65LHjG>iCrT%ChC-X0P48ySXBDApLA%co-8s0LNBS2e&U+ z$9KKTFD84o->V;Bf=ie^ch5}x`Ev0{cPU8D6OI_??D{E|HvY4-X0c?Pm$mkLx$V#Q z57L$D)@VPNT_O)A+Xe$R0Bv#_413T`U|!mNlH!;dSQIx_+yy5)|0)i@ElQnodfw!)+&P z0IB7spzkwkPyJS6QD`$?b~$O0wJaJ@3A7AZuYXHdg0)3R;h^A169}YuFpQ>faw~U! z^#MidO*v`+5a6#bqfkDZ>C0<^l5$xxly#fGGSCA0Z3t{5JNPJg!Ophn6Hm^BR?MI0 zW&&NaeI=RZ>O>igP~9*jWPR*$8-u>_o?mRi6}}$`2E_5Qz!#Boqh_lL6Vn+a=jkTG zF^cXMfsCwLrd;|8!DIgPRewqtz~;bQ8lQ?$BHrf%P2kpG}2df?$vaH@@DSV7_E>1MN4Y;?xX$B-vNbelN~C+^f~`t_g9ePG zKGgU0s*UvSPBc6;4{>janBW4~xdU42s7i5+p-RXw%N^lP82tV7DE4ZT1bA~zL!J(d z-32l|2xm}ZEydkKj7GL_A@>HNG?h(HuZscB@l z`$2WzUM_-*_fu*T!9FE<*wRXPjJI2tpa9B{8(Its2A`3M0Zoo+qJ zfRR$ddj1hhAx4Xw6Mt566RlI_O;!+zC*F^DFB99u-fn+a;<<3SK+({L4p{KAkx%Z5 z4^PHzl;YljcpK6_KC&@XH})!c7<@N7uD;}vQi(xAQ;wWP$RI25tOnnpBqa4RIZdW_ zginm|;(Mw?<(&`bM}Wg;+3P2sY;}zQ052Jj@~ZKV%e;AwfQTr4t>sCY$nMK3drmA8 z9=B|u{yk;}k*op@qR5SYX0BoOVJkZnspq6ppSMBX`({Z;R>F(Cwd19a&~j`X-(H;K zB#cEBt;hL6s}w-65gxJyy7(TkTiN7;T&=c>n_U!qdl4<}2xd7PVn7~=##-hYP?Tjj zfdu$EsCO7>Vy{ls{BD#v^l3K^O0450AKltQLZ{E zx}lg+oYnP05>}2BBoC6fRrmBo;;e;$IVO4LYBjvii>`{W^ zE~%azW_8FEd`glUq--x`=}c0sRvENqO5$4D5}39Nv}Np*hdj9z@h%`bMn*1CwQWqd z6wf;1edk+SB_GIe8%^Ax0k{(-oOY(xEY(FtL7)oUzd!fS_v0A0DOiYyFGlt(6`~c4Cm6 ztNn2}?DQUhMb@Qk@+^!YbaSGCNyL7+b!GY+SpgQ4d)$nV4mPkQ&(2L}{4h01td()0 zURX!Wh|~Ut{2ADvkgSa84obG~GfvPz6}p0Y5)fgyYkH~rAkc+}4~ibUiYJR*nFD9w zK3}&vW{g*cPx-sdt8Qx=C>q5PHZ7msiw*Sn0Inw+GyJNHo$QcH>4dF|o!nK7ja}A^ zFV&pFO(#5CK3H2wsOY5&h zfL6Ow$|F$xGobiAu0Zh}^nl_U|5N`_j5zaqyZFEiur2cb^7z3h%y~I`&b}*WcK2q7mLsL-Bn0fjP(0cHx=zDlyX# z>XY7s#R^kUiva=|fDl3}2taIH`N5K;ZQHO#2)6|xYPVPZSLvPhL|B7jKdm zO-TmrF}rIl9zz*%n$5skE>dwkXW4*`nqEUCK~hK`1Hesi9H z*s2;n2oBhS8g}gZ0b=cH>Sk8-vVZ0}JNtJ63-cgruaG7_DTe95HGp9NC%t^gaggV^!Z>`7u=@5Bb)*+(_WqW}^}OY85|G)C;@x5EX>3mf^$ z3nD1*z>aVf>fM~gkw=OKD!98$H&5J$MAw`4J3k6Tq!97x4p8Q33TzXu>hzp=;L-^O zL`PA4L(8~2>R|PQ>gpz0K@!rrK%8=@%q}PME4Y$tKd*DuR{+Qh1iUk+e5Wx=!wAT2 zuLDgqa_)3Q?3WI7ROvkyhr3iaFY5x~59#eQS;&(F&>yXF9u;Cd6~c-JZI;$}@AXck zRe|L>OE_X}HFMJ)y7+8wCp6?pPuoMOG>IQj4q@(BHlD&)>~^@=U2YaXCZiBfh8C%*_6t*5)D_oMVvV{}XGK3T_M z__~Zp#$H&i8Ju71N4xpF4ExoL=(dnZe0yw(X`b=D?)+=xryquCCo@#|(LQJDQ!DdG zUt?)JwHY5c{&(1`an2mG-Zdbg{_$`V2Ke0HEpSu-+*!Y2S!$Fq*$+L2V8YN zVl|oW%%QtwuS=Uk1>E_LO1>D9&1;7v7P|RSqS#D zv@ev?ji2C24}V7gOX~Xf@h@jI`@gup*#EDlMeHp9EVcz>|2Ns!UqUb;A-I2WPkUr0 zX#-PNE+oKKH<`WbuV`zT58Z8|%ZN2MWJow&Xr5eRElV3p)}dOJvFxl90|S-9B%ZyE z6>m5RSq_PKVHH{6|1Aj<$o6O-?@JpQSDPsrbk$C2_LmR%d1|`*2UJrLTIDv*OE!Ly z=NxwKvVembk9mJKX;bAnq+;{p6YKVk-)O1t{#rS!H#o^>e(-%3cny9m=|=WYT9#qf zkK8ZR&_Q7#Rbg(@nf^HE+QfI3(2M&`fc1CihkA6fYBnyf8fD$lV^ipPbvmu~pArxT z4gIjTwE6MHJzXzpY~t&e!RFD0Fi}q2w+8j-8h}nj_Rx*;K~;m;s*Ak~rX;I7XZz{R z`B!nQh_2uP!-o3Kf?lG9y#~}S4;w;69qyVh8SyXbGc}h4s}`Q~XO}Bi<~NYsNUDO0 z{SlD#Avw_ATWRRoP?@EJTXcN#L%hbVWrUpLxyozp@nl9eoR>>GA-5DSze-?pl!kuB z+5$|Z4Z>13uRwy6u^oP?$%z^EMpWSik>!b{5`HlLVbcKbs~3LaRs4QP@v91|!M}OY+c^!e08zHSdOiU44|Z#XNNK z^yXaYEi|q+7bK6=T-Kwi)ZFT(eLx>v*BxNvm0=}}L&J)Rb!(?zc1V46^LGyoY5g&_ zci$C;_ML(AY=2-uL8dhvgx=4X!8QApB zq3-#1_rnu`jyIR|p|s4B6(b3B9(M4d=;GK|5Op^RBU)pSE>AuwybQ1TOX=#+X(zzI z*=lHoEz{Ab)8ibs-5|wva)c^v%Fgl7;YNE|vluwdvX8*Yt=w5T853y4N?ROZaF|yV zaW2{@-;?e5Rk*ab82Rl{VY{1np*K~`rKkT^a>*fsL!mP=%PuOsWmx}DhP4*)B4)P7e&bfRuN*`s2x{YnroUT|JXc@=!ip-c3@PRP$-1MLV3U_(E~L(v zgeviGOuP9AH+xg_uaASu<}#J#F4ZI7CZ@hjGDIH3w*p9BsBNhNkIqA4^ z9lMtty=D+k8XT!*BywR8M8g!Zs{$H=EfI)6Z@eoz{#eUh-iIpvgQTWH*FCpL`9>ta zeffpFNX?0{Y52zk7FEg`vu3mq->5(e%Q^HecfdpBdwYyaCWoDVm*PEHlEqB3U>L9! zM>IIkgbV%S2#-9hKyUWnjZAA zQ|S0?8Ci*N(D`m+97FKrg%s{XqY#cuXX1%g+TM-Gl_t3S{HlthdOjx6Wz4E* zc6aM%3*DFnWznI0I*Q{@EJ~Iq1jF0a2gYVd9;Aoji4MUyHP9D?R~!RyqxMLFr62O> z%>F!CUZmkc%UI(>na8?)IAIT-N2=PgOV{shl3iHno$!x&m4&zQ6QRlvv`-XZr>eucU_@NPizF9q6Zo^Wnvkq~E$Wd1?=%U~~dP)#QlUY?{Sg_V_b+pbc zQFrTp3&AMAcJtGs`Y~SP`M&Qs_cjSqe6>A;;zP2*`5z4`G<)KZ4Cfc+31m!l)5Zcd z4PcHM5uZ}S5rjW}vmJZ1=Yy7#c@Ksufv&!nL&f_x(u-!HHoF!BUUbN5jJJKNw);}P=(;{jT7=h}qA#pZF8)59)N(B*Nv{ot;92C`mFPS9fI4_+!%_eSXDrxO z$hD^AOO);UvFHXS_mjUW}0cyDuGv+0fZclK)coSZz{cv#VEJ%D3ka-3z?C==+(a3 zjV%w9j@gGPFqkJlSIn1Vx|eg*9H~ShHu;pM^$u3Se0h(>uK4FeAg23|xGasV!GoYXewjA9OQb2gAe>);pu%)-xW6^3zX}NrfK2~DA4({eG5tshCd(e-?PhZ^$}<$Y(f9p z&o=z^DHObpBX$gI%w12D|>l_wmp^rP=4(e}P#4LRcIuDPeq|BoM5uEIdDZ zzhMIuNqE^wm?f>8oLxw`x!C_3ma0mfvLoO|7`pO>6Y|%1qlbm@u`=u_fwD!miX>X? zp-~!uRca9-?#|&t+PznaX}YxHsPBFb0d}0wsZsl##xN2b5=UR_=0tuec}W3BA}#S7 z-wNT6;*g@yHJ0l3(JBo2FrXbYn3aYlKnsU+&|a}>Peuv*ZLyTQm-4e(HIJ5vimcYC#$Gqpk$kdA1FlCcdx&E63ubsl(Qw5x;z(%FOP zvqzQ1cZWB?f7hm_6>`Rb;T72X#lB}pS>`)uK%!a=yNZg`v=W+693W&TA_WSJ3XaJk z7?nj^t;bb&2g8_r2&D#vV*pzJC(qYM(vvU_O-ratoUNa~V8u9xf=Jg~g#7I?6xCp+ zN}YoLMA7$2vTeh$CqnxeJ>?}?h+~3#^xG7w64eg&P)E@ovKqq^Gqp1p|ipum>-f1kMqQ&S!1C~I`J9zLz(5Q*s%XTlZU4X z9ptXjpV{Gj2g9Pg79`yKxVwGRu^N%b(S^u+y?%Usyrb9C^9AI+@)EK|^wv7#X=KmM zz>yQ9@#)L1;h2$>d_6gfCB8i2;VB*n>|UZ_|I+2x7H(1}uuf7UDHu~zeSCdb6MN;? z(m70xY_D%Hw==v3xXghFCQdW%C6q0N_*^Gl-w+R% z3uoSKXG0X)Y^~|JtX3AW7|E~R+0u*DHW#ZK)c~tGRhAc>=XBPQeN9yaA%JQpY&Y8c zwONfZx1^mP${hBuZ0QB#;Kx*YRm%?%;pD2d7ntZ$?YnFA#p29%YpXk`p0*vuTjJN7ppg4;hxJosr5D@qq+;@f6AfVLwtN+N|_z2W-dz6GmvF&?@H8n z^QG-Pe_`|5xG%b^JCi#x``3V}wk`nZ9Br=me>Ns~+rN*0b3YE&f9*^xyj=g@nYjMF zGx2cz_bhKPWh{b-8%6Tb6Hd@y(sc$gN^|He&J>m36tjb!D+qS~#`!b{p-UYZPi(}v zxTrg}i%C66HlZa+W1zFrR_ia&>M`+UxMT@4%iiA8; zKS~oF&w)=Yda1Yv9i74J=MvM$RpC>*e55vuPe|*ym^rdH4iOYm>`q>z@lymS=$y8^ zN}sm%?XB@Xl1E;L=9{rZMqXRyP(MsZDFR>^(~JH4jwWVTKZv?{q?WQZ!d5iY$4^Fy zPEh+IR8*snQ~s_%r{*8Zm-L2-p^#C3CI)dzxQXo(sk@XLTx4*9|MbDi9=kN7K44kn z)nq~usp^`Ljohx1G07Kcy{T4m2z?E-nU15T92YRB<>+&mF}8~rr15SELjJY{oD{$g zoE0kS4-Rsfxhj~XX97Vv4RciAHx6ljGubBNHi+dWcJT8iUuRQl{E5B-4s(Q@!T#Iw zNGR=Gt?ipHKw_A;h+EQqFPEm_b`6T-!C>vow7(}~dT&2Hgbv!yTFNGDup$0e&>-h{7e8RDgLv5h73 zzY};1U#lavh-QV((uY?U&lXK=8{39!n=EaeDmQd&_m6RHtrt|yG72Q$g#m@3nph{K z>y1Nbe1)Cre!@Yn>IEP^G60=WH7ZI$;^gcBzJ}q+s{Q}R);Y!o5;bhQw%u-R+t$|h z*2dO$r?$4n*4o;(ZEbDaZohrrAK#NVc_*2Z$z*;`PEO8s?)wsO`@{TJ>)h!^^DQal zN@sXUuzs^aLOQ#0IfY^j`+Bd>lm}rHOHtwK=fZ}V*TiY*ylUIi>7Ck|tuR24FT2|L zGb6N>Gd;P;2+q1ZrPxS@i}h@QtO-aj$d*~VJ>6Td$<%KD{W>jC-brMAhkxOnG7U6H z-Sb3=cW2EwKo!+b|5HN8CNt3Pg45hL|T0PfN;Pvt>nRDfMu8bUG&GKXwRRQ5srJNRi z`OXyrq`bqcHpkxh*6j-^*+Qz?TvWfSn_ItX$zPmh5-cc2Y2EWw+hmhFRxKJXXgwRJ zEwj|`%o1kjRwCw;Mvl!nL>(ob7;FYhRuzAnq4CBBTW9|iQbtg@7&nfeT^=MZsE!g5 z{r7_PwGD^7!KVGM5$nm29>Ct&T{vg$%+I68%i0>%WOC7~x1f4)^P7V|0bzf44EH6e zYw9xk-yQ5W6`PTR$?E0YDp#G~>Q?YrcsX_4d%%ipCh?>^-!40(zXi(rdW#g_yX@{C z-PHk3evSU`;qwsb8X1qS*Oq8A`#c2te8YMZ0NH+5S~=G0B

9w@vEA}9zra}U8kLPK8v=$q+sz)<-Vy8mg30}(X5 zK!Vee4hjdm@NfqfNa1g24L`MwUPt{IzDguow*3V>^p72+_Bp?Yk)cLt1y{8&TU-nClR>Owt*%%L{#7x!6nm` zLBRIN))WdgM#yz2anQCDS1#Q;JQTn_w}3qeVH_NQQaH{e7M{ukcZGZt*3(Hm@zkt%%}=5eczwG7T&f+$@VZLK3+cBqVnc%)>V?K&h7r!POd38sJ*o$ zDtqkS|D{n{mJb%7h3bf#3xu~|z`#I7MS+`Lhs^*IETKJLWnlNs)kt%gkV$W<^q(o8 z>NQ^m^G9FSED-)*(PrU&Y*f5!AFVIEEj1{Fm)d$hZ0`C}!*yqTTLBfENeG@85AZJN>UN z@s?^zew0IFgkj;0FQo%yyBq7?j%}$lmND$lGZD~8f05j;xt(UX(+Ggw=f>x~GH@sL zFo%XCUMXq3`T{LA0ZMenQVIn`$hdA_PoN*|MkF zQ)Ucw@OpZV>AE=@$ce)lB0zjYh6t7fQ|dkd3PWG>W}gS&D1@t$3y|pU)2#M?1bD8^^O_M2z1GB`r-U#O7i{Lv(B7T1-`d60gHsh z3W@6mW+nNAEP-)JLJNwVYS?NXSPQaXppmTPQ|C>=BZleo;WoHyEd#r=|FGi%N=I;J-qWLt~6fYC1Zh6 z-&Wc;YVaiymW5V5t(C0dI^v>+a&Hy6zFL^sv9&0X%SO=A~h z0PE_-Wfsta@niFix8w!Chd;hqqzTtxwX;B9U{-{(aulq2?|KCQ(} z2fSWb41O)qp2%^-;Kjn76Ll@7qAI4s6iCJ4mO~#Dp;usYd^mg!7hvfNs-}#NctzfF z7FU5jlgDu&)pvTp?xvqw;mOKHaniEJdD1NPgcr8D&$5PeQh#=~vC&>WgD69JxYX{P z@|Ib0<}b$KE?QEaZDZt+LrZRI_GQR5957-?J`K0ZFZbvZiplY?*HY0cq()o10X{CI zR8dv^hr%c@KZJBiKNXRq!wW2*cs9Gq5)`b?x#XPXnWKtjKlb zJy32`Aa51=Y5lB^FMMrmz$C{^4CE`H{C2n+n_pzej$VG5C3nKK;d%n8mR4hg<>y4o z&r6Cx{5V&Nx;9x}A4@;R5{hM#^41{035~xb?le2eJ^DVufnt-6abJH*(=1U-Ux~G0 z)XRElt?8>7^|L~fZE|ewS)rc3#FP(OyD4gzN_6nCwFBk%1EL8>TmuaQD}b4XB0LqE zy7*FvZy|FW4Aq|0!!OA^)bPPbC}V|U(q|4;lEbP zph%p<0a;0CCug=xq&92EgFs6v_(@o#0i9JVd3B=oPSVVv8_C>?8GD@9J)|Kh0R=rx z4qv@m$V@@m=uGm-x=)1n#i#%IM5}dm&S+4LU&X6`c~*!Rt>$R4fM~5Cng&uC!~s{f z&yJ9ZX)O)qv7=<*P-UB(X5z$QGR!+pEKG6RpQ&(8R$E8iMc0#BY2X@T|7@`K2`+IG zQT1ix2iRHZU+pbyxN?~Gk?@gw4IwWkXa@Iw!YWvmgTx0Ozt{;=gHz#zVw02c(nNeF z>ECgP#-w)4Fn(m!?IOC$frP-vGt>Jq&)-JkD>$2T^Gzc#bXb*XlsFt3WR4rn}s|5!Gp zDN-7QG-E4q=tgI)PPy8SDq?$a)Tc`@*;^gedar_i3422*XJ9NIMiO&*oiP`5aqJXl zoi`;J{9T%}1w0u^7#ba3IyEyy*F#eTd}7Euu5HWZ z;xu~sUj0M2m!Nb-+&Ui4cZczrUyk}X4-*~*|ws%9&#>D%Yxq2(cjOs~C} z4a15ED4*uk@p0+>ttE8z2Q_{HsCs3UEI!)XbE0YFPYoU??Q&BL%TU7g)H)SJC*pi~ z`5F~`0#sy9nWrC=Gz^`4ss!puJyTim9qzG9CjjEv$Hbsc*>SrZXML-IxEHLNZGo=a z!e3QNSKTfd&A3G?h2O*~rtc^&Rus3GKcy}nQe&tYF&#rV7s-k$^P4Z$i)-%}{oS~R z^>=F85_1Ie@koTpPx}pvTkqvt5?nj(phy2OdFQ3&)T}o-8)N0qmPUDfh&cRxeNgko zUIRX71a2(LH*CCST}S5zsAnrFp}YKgcS)u)=zLETN!FTVIR544E-AGG++lK5VO7ev zSoI;EJpU36PAWs4H8B$w9|0sEk4nGp_!4<_vJ-0e206`P)MvWOv2(I3hyZYH)NX@m z=^7!in{*RS$}hpdkkM$hU!{8c(tQw$Qh*HU;v^q9e6xJ-fUIiB(|pz=NaNVppEl6_ zJig&6omu7I2hZ5@d0il|Lrk9O29R=x^;#fyLTP+a}kM`h7Uzy z^EvtvbI?&HyyLe<{8HoX(S$MrJ)L_T$)`R?ec*7LDB6DDLUydJ4rddp?1Z&QRCft>UR5m5!=J7M$6FiU=`A%pJJ2b zDTPLZ3gp^%|3LrPKBZm^$#KjUA81Q?gbVG<3b!8s&=l{P^MsI5+=xr=T81 z_-*3V-yxt-_cy577dsY7m$gxEP`evjuI+Yqpq;iNt0QJ56I{H!jc=v4-1_WB$fTvm zSio+Y*j*U7QR!A(9AD;eVLk#R&N&+W>BMNw>y~tbg*{Exf75-Fq#rGzxq$3`7p(#3 z*3pgVUbP}~G35^HQ1-}mOS#dglr@Xc95=0xOl6meuAC#m+CmfRWfylwMIKC%+C(Gk zbC!{s1p0)kQDxhcmBQ0X$Pk%kR{=7-n!hZCFRO=*X|rm6R2yAKIa&weCT;RjuVaBd zri7*xTb=RguN*>Iv3hY()j+VOcpX0x@>%t@b>y<|32Lt32w2M6$*glt!fZG3e)Y%S z)6!1bsG$v`O(k^MmO1%TDZgqbTaOz&GWEL+%Nm`MO!S)1g1aYKS3g_~S1R}vM(R7R z*krtp*`nDVBPd^;#s`=qdv<3RaOqKcup)lHqni9hCTG*~z-G7;6riw0$!#vGJkRmT zexue`54qU0$vw@ENj0@KT({FbrE6WLK$wcay#@)feQfXkH-y>tLN43WLtctDKOF{F z$z4xF&{lHxH3w#zh82mgymI)2L|nAqWXcJl!S@WNME|GZ-W;|7K4|P!iHXzVob{{I z9F#$d0l9gmq*OXkb|9pifLd{xO6cy&JV zhM4zHsmPEiw8rydzV8qZM09d0f=3JAnJQn0hRQ7tNMi($w*9niVEc zzesrPpDy0UBf)$JG_-p5SxREMuF=HwEv}-k<2E0f>3=_o@ORQ2tY)0?Npf(t38Akt zQ*|EWqA_03QJ=Qm3fA>^?1$Q@R=dBd0=f2Hr8pwNx~X8LW4ICcFUK*C92Pn(tgQ)m z-21NjihwRfn&XiBbFa+Ld!O8%0d+6?V&0Lz9PN{wRU}VXeO%rj>E@P{yG*Id3m6!F zP4iF;vy#Qy@f@ z$9DEXznX1#_hYLBbKv!Gu~d0V3vBbO3n?%*Lb9C0_-Ui$qDyz>&`d(N*_A7rxLsO9 zb@)#EyR5c)X)OFQ!;k~0bIXuRXYjL&BK1_Qj|p?4xk^!bjb3}9@Ax~?1v0T-s(H+O z+z2pqPiw!O#6>o_2<`NMVUb5 zLa63eWX^Y7jDCzQ8q&}+)#Tfv{dklq9FJ1SEGP0Kzc%aV(VVnZAS{A6c` z;TzjQa!)<^kE@Y{H5PVIYs8Ph_vCf?=4#DX%&{jpG$9e8$2GK*l5out+VTU5@={XY zjiJBDmzVqZ?J@XBqz1{FmJo^?PJSFpuzBlK_g5qQk=HpP_xm ze}nS1GHa^K`Dx@Oh2~7(??nRIdrkp@{(ykG6S^o&ugIiaZMld&(#G6GWt!HG1)VYO zpqTaHs5}~yFxjS1d8`c~^yTWC36)GAn_~6ysgXr1$PQQ?iQ2D1h|v9n0jBHI0Nh_2 zBmqu5F}0Z{PKrmPeugANqm5IkX%A_Gx+kdph4g*7Z9bFsRHoDXoavD2%u@Hi*Uo1fGsu;k8`PRiOEE<$uE~-@x=*^8Br2yrT{;ft?6Er5 z6LhBL&LAk72jL)a>$$N!|6xTs*(p?b#tu`CQnL<(TnMzkw=Jm%5Vycf18qu1jxU`s z>5|>WuPoQgd>KXSM}kqC668lFPBu}Mj{@w1;(^{uFzKXLi>F)Nj3Q}qGxl!+iz$PL zFg@sPDvT@R^fmaEQ>l)_Hp+s()N$?mS`T60$tG7U*36v|+o3hZk}fh{!nb~X?_a>@ z!r;U8tb8)dD-*)AYcU2&Bk$rpDK!mN@VdlQ)0W6d?qo#eGZTB+Ov`!~#;xPh2*RAu z1O@a@v{3U1NS3KrpYF8?b-$v8y_|$hzsS{39f>KkQ66n(U;O5}Bo+l)H?*?dCJ}-s zU0!6g!t>gm?&O@2oUL@auBgOTF_hX=@rMd_C2Pd>r;;|zat#4Iy%?N7zY4UblJ49d z+eIU$SZaBWGxqmA2F>9DHYZNt!!r1i?$D;ze9CObIxwLaUB7kIy`OcJKE-V5h{)P7 zy6q3nhapyfUFT7qe9@;j=1k~-P}euyRG)a1=t;hYt{~uymW32!sK}Jjr(S-PwQNUi zwCWqESIOBD$SDF35Br$Y%fe8$wj{1y5WpHUT>-RA%03!5tg)EPq&FEVkCRxi>5Ko` zy4t#YqvZgbmV(Wpmj;oW@x88SPLw>Q)gZ%>w7dM_nyV@r6}rGms;*lYpN{IuP8IRf z$9rnewT?P=ogC!TpP+ooP0)SgxARTBX+qmSlHHCTn~1`8j}E(_~AuH+JeCKJe!XlqOIn^J_GKhqSA7-MAneRo!_!jC^ACV4ibA)ONEi z&)k1yQxoP2OHU)>xK2OQ+ag}npp40rfV?r#oRaf3rfev-nXIu=N)5M7Ze2GuK!J|| z-{}0_ECTq}3@#*xP8IPB1=5oVOy&J?9COe6I`TiY>x{&Wssy9I_hHFMT}W!VGCyr{;o7 z{u?Pb2ib}^S2Ox%ZI}3{5kG2X3@(L zXYke4g%G9r#f3~xR%Im4sfUt^JCW1YMsi^FCI2ONfub`WFW@V+jX;hX*fJ3>uh} z$ebq#j;j4OHH|n+A>>Wa7Rc{Fhw#$g&a@U{yiq4A$81JKNJ>rNjJ>Yz7(o*zcf-_o ztjj=jK0FdZ$+o%=%#sgO>}88Tfqg&0Mkp>YaHJn0*VQ0dE8cX=*lX~Yq`3G#AxLv@ zV%brBFEy7m!G^N!*Ua+%+A0e8WdU(;YA}5F@tJUmin}o{v?w0jjf5U3mN<DOP3+cT4^vpuGtZ=wA$m@KKtj)HdZ9J5rN*E>47Y8;Gso!LAF!*3wI`8`7d<}o zbPB@@%7{3zqfIdxZaTenk(;@rBMCmz()N#CFMgLZ1!X)oGOMJ-ZCkfdcmRm?qM3&b zYOlQWTRe{D&*r>)MS4L@VV%g+=m|OLv%ZJzRs&b~Nrht|d^EdMtF=sA!=(0DR9Y+8tQrT3E$Ql!af3RhFbE8-kGVlg%AHKFpScHxjTvDhCMnn@B1uLHmULqSW{zfq zBoOY4Ws2u(tJS^Id%5Ca@=5S*e&_ZkF=}$7zUTb%f^-n(2F;a> z6DRysfR^GD`Na%_gQNsqaGtAhOh95N>CXrT7L?!dsr--ItRsauVS$4Q@bi20DpYmA z6jqWSiTOh#m_g43w2A(@RI=`=4gke7q&m(S^@#Wj;^oG?EY!l-2Xz1{Aqr~Qg9;VU zr#Fjh=U`2Z=D&%bTV4S*;}Y8U6~Fk2LJ0PmjR-OT|LWe_z0wWWyWO4GivrU(ii_|R z*lP>Q$t(#_3#*F6U>`(y!GQEv0;s*QRWL4se+dwrA$0O!yZNBOF$x<&4e$MdVdoHH zqbX`lea*DJYSe)4v0TL;gmw&34o-o6%2ndsuZckCs&`_?IqffG~(P4g_RP;A-Et_*ZFc zXdWl9bUZHE#}7*BV|ft(;?wQ-<;NyAK8^?Ke*cR6@$>-})3|tV%HHxN_kNWYjnId_ z-4B4HfnD>X{o68mKMo707V5dmF>C0l>9)Q8pwh&(3j*PPoo9GW`&_JjGXQmX=YXc# z&S_*vv0M}d#s5NWrO81dg7^UW0AxSh$G+ruy35|X#Xq+YX<@hB+;ZI*bbV1I8@gCP}+rRS- z40M((-)XQzNVXa&od*(^-91;$0eG_}iJ7(7@IpZyG9kGc^EO+nK$BbIQNvToG^zF; z^B0NUY4c_IJ;`wa>h=;D37bWolbpwKl$e{-%g!_3@@!cX3Fn?0Ycu>VESZUKoh|YH?O+R zK4I@_7Lzxmp2?U`T|N*8_s1UZ$@6cJ!RSZuxf-bn@xnvfBf_(MJJ|DJ3V?esMc;tcGI(20UvHi zE9>9;EmO&gbnr4XmB%w}fs>mlM6?>C`u5cWQ74n3`ZnjE>f~Lkeeg4Bfr@S=--_#8 zrfH}zM>d`LIoH#sl=wF{1`sk5ZXn{jdo0#DMh1MJK*ap!O}}sK%1D2ZJLQT!BXR{h z4gOr>u^9bZrs0>=K|%cO$)N|Ig{eiqUSRzzfn1_i)IHsP^L`bd8vuB{@_U58WEjSY zKnIY4iD{4*YFwJW_F5*B#R~Kw^^^MN1KV7FbIe*sbt?NwGVR|Wk)M!;^j*VY=%G@B zERL^ljcYu@i4iWn(};tQoAR5C<0ccxR!KJr@Yc|Q7I#)1?wg)fy6DE*MK?anN?r;g znd0++6ewc~Y3czj5KXBA)AP*ofETLHmi&JG+N%(vvnqWUqsB69*M$vf))#hK^snTn z{7zr1$$FXJiTt*z>YO6*1N=e!Nhu`y2E^GNUw@%aW)CmOZ|B8Up{VQB{)lngG?cwm z^Nc2=uwY|u0&|T-9%&dXx2GA)~rk?MGS!a zVn5ZQ{u*zKn)j7w!SwD388{DD7-_vZb`ZWe$1TrQDM;}a1fBlX1q;1_rB!I5JOY)G z&xy;Yxzb|~>{zwK!g2wXkE8ChflA^~b;}qKV>+ik+b+277OX92=tew=pvw9jU?`SF zWsA4wQ^h$yw4DWeRaO&0!?wJQdwvz#>OUX&{3*#9@-b7Kx;!_88`v!eTvAMqU5V7GhhCb9 zj1u+=JZJboi11Z`be0EXn5>pZeZP|5k_g?SI4Du4gN1dQg0pi}1vB=gEjCxlGWzK+ z3g{Q#*LT>*7UA*^l*Q*q7P!cZ#OlsvUz8AKIqaPYIc}hlI4DE9b;bC~`2;75P5tT- z!(^l-4yB=IL_)Zbv*&8dbbhIqu871c@zO*B{HpxX+T+%UHXr^7W_EI<>YK||Oa}!^ zF?9=$5!>Z-eS4au=<0|MU#%7I0mNfa7a}7R)b!OnTnW6w%(g~8?9sRhF zQqz7Bt~2#a(j_i*59oG0aKM;}h0_{-s$gqC4VY%6gNj=xa4N-RzL{`O&Hh~%}_zs6#64Ij3pJtdX<<68=si8;{6*CsLQgmmN%0HG;F@lUJjjU>?44HxE#OJ72BhGckH{B=w!OOjlBsM<9( z$z-UIEW!~l=?^jwnNJ5{Y^A2zdU|)G-Wzpg2gxrM=iP_Qo66K)D;-H3bjJWMc=jZ- zs#fl}a}>tt73tUQxALuCHRie#fN<&g%v9Tklk|`5nJ;584c6xwWG@=R#y!)M42^*6 zqGBWlbOrA1bl_SGS;;s1&SyjU>2Kp<6Kc!dWNg+Y7Xqu%4_f;^CPe)XX?DnOoyoiP z*}{K_cgODDM`9LjP^k_@a9vKV{-8v7OEX6A)9^oeI8*p1>)T(^o?>D z43}OnHOyU0!Nx}ti^RNqgu0iN8E@H}!*CL0J1gM&dZGSpj?mdJn=e*xu=cqB)^1ov zjP49z|A9Y4xTr~X1qBo%vJ~Oud%WNOXofgl=zue~jS`f{IW#cll2?Lfl#3z8cKN$-^JcQKXjrH!)p4of_D2}+O^iHzDwM6b9)U=6*_jl!X?BJ4^b8_ zuI?N!p(^v`^oh@R5EyQxeE>_pm0geBqGhmhN0P=VV)At2bhQwJLS-b`@>u@yRW-w( zX;UO3Av=6rX~Npcbv=@y%7~5T*9*n*DBd0DLh>Qfqo_fz#AR@Z{ashi{FLoZZ*Mdy z?2Kbj|HckGCW23~8%tq~b_CNeqGb`pao|2?;hJ(nIdjz{7HG0KEWJ#-wfwcd(9rRe zOLv=nS0v8pNPn>E)tSmQJ|4j@hc=2d#1P!C2`%vFKAvW}cSkjnTf4(w@RZMPzpl?p zV^sZt&K;QmTIb52iP@3tx6oWCne7h+3UlL9)+k=Za)?j=MZWWv1|j**9Rnu((Y3Fc zxs%(xRMK0$24MGW+hx$4gjLt^HrO~RBKVpjm~3Zw&)U7^fr@Qv*dW2WT^6tI$SyFiD1c|-&ZkpVT850?$^=A7|7aO= z3>MwaxMP&W)e=EYE4AI5^!-IW6arC&kUZqndMo{quUVy- zSX=9uGl%>Xhjg zJDz7b)0IWg>TtYyXf+CUOrA_B<6qm+vwDeVzM{_oOLj+TH?Ad6(mxc?4#se-!ukts zR>7Q0#}G{pI9WzhG8p#ihT;zu9|%-GPls%H`v7&FLr}XL@ot4u4(~0}z~S;A8Jq67 zI@S{ge_dUxnoWb(xJ8xoRMDewZ7P z?IPHJ$6GT0G76N}StvZCJuP;V3NGXvbJLu*(4`()`Dz81`So+kgf-zd*q~nA|2nwJ zVH`MA$S2u&dpbRmmEF2Q+vk91mIWW()7M0oq#v@J+@VZ{kfbxx7Vsk;xIa05-x!7+ z`;bP@(m(mW!sF($xrg$GeQDzU>Vw4inBsHT ztH#Q%mZ{r zvQ~>7M*|xM`0Svsnyh0`*G%zhSvE#j^*ktL%c1md1B<+2K0_`2INGl?hN{P~3k8g! z%BKmXH>A!I^G{-ndk?vXNlV$+W=tWiodh$pI&)-*+wA=jdcX2~ud52OB+)vvy)J(0 zwexVOx_NbbPM<`eWBd!FSmP~WQ3BlOcj&_;dB+2L1SV zd&W&sY$@#`6Hliv-?&Yb;39J)dpV}8A-<`dUrFqjXC^*P{7D5dZxz^!Q9Hh_)lA~z zQi}AWLmN;wJj1RQ6l9Ywm{xs=JzFbkgkN+h8dXpWdx5dqcOhT#B7<@mib`o>3vjs% z&^M;25M4j!z_%0}H{?+prv|WJ%~RW(Ka^J3c2DoLRd(wSagZkaDKyTxPaMQBMLOjR zCYqoAdg6+uMf-HM5%*tYZpMsGZA#WP&s1;HBE9_y{j1JsW|^cq%?mzP>YaA$L)@p! zA4cObT;9Zx8PpqJZ*PdshMkmQE+uzvLW@GytKiidjKhRG583`of)BuRtf0Nx;1S+x zlhZcwyh2|MUXYqAAmG_YP1Nvht&tmWsYiWW%czlsT?i*{%`;K2d+=K4PzhCplv;NP zZgzxrOyu(78rE?9(JxSw$FS(4HrkLE;5A#!DpDKQFXHPT?VTuX6!jgHCA>l=c)!Mdj%7HdSG)Q z`Bb+%b~V@qWy(9S%0IUKwv1Z`$adaE7?ZD@^y)%q1jfXG1bq-80@vL)^rBpcpH=DO z9gQta5W;A{c8q$nIA2ZpCL#HWVhEK5-w@07`BYD?XCB4<2(XbHoF0nlN>3t`{c-BE zv&+KnVwcdob`Py6BvG_G!xAAz2anwp&$qHJ+h&QEt9QX9Q6c%ZeC2zmTqi{CY4^6!BKvl~5?i72;&faWf}{=6(xSKs+O)~v47VN{}ScO$GWVp-A)ZaS}2 zxDDm>t%{@K$;~442t>DNt|?U_A%@?TSii7r=4I!`oPes4F=ZmZJGGKV(js)B8FMBy zAhw-^Cyxi}o}#rVti0Exh1{d(Y$<-YVbb^aZrP5*6egOGfQPmxQhCOXcAN%?dA%~4 zTkP=$iXc_JayB&%Clv#`XsQsD^6ww^`_HuVlLJp!M6sP#cO4!-cAw6r9204EqwhPZ z3JIxxX94*HB9h@1DW12&eJfZNQqW-IsJtbuWwjrTYj*qR0C)Ue?~)SO3_MTN@N(`Ggy7*7-ndKqtOMx0n_g z>GN&bHIj8UM%SW zjqgkASmiuz_Vl86igb4JtCNt-O6?p&7IFk`t0HJgGcTRy$pwced$0_XBg+FFCPwCR zU1oyLV^vgQK?|7LQJ4FnWZENl#hu1^PGS`^4;GHbndp+wujOg^iILDbq%P}v$s~#T zi9o>M0WYOstZphZRz4oLESgv30V}YPO^NnGE_^B?{Rp)C6 ze#w!f``B_pz;G)Gtn7RJ>$1_*t2FDLJ+HTuCK6pIrSd*B60wr>egxIpp$Ab1qqP8} zyD#>F2^#sJ8O@Q|41_2lOOr zpD1trr2l^TT_FAV!X_)G-~>elbh6asgd-g}_QFK)TUG26by%DTHmQH3QP`)WR}{qY zD-QCYe1}_$L}{R#`8E~rgj_y0G>s%st6OuZ5OKj<5$_2(D^OL&UuMP$`@jlCRdKD6 zxSPk%M*oYqXd7kwQJhI1mhApJE^{kVLOgkQ=m0CG_^7OcD%~AdIHTIxuT`IH-WVma zu6X%2A@fv`eG+FGhxYOTUIL!ml_#ATMNWz8P3$~=+W|1(&hO5yDM{m|7@Zw(VrRFA zO|>vAypKvZQFoW!l1{hWj4_0Q;#h2au7O)(j5EH`IzqP(OxYXS379Kzz7vKZKN|hX zOq#a-Tv%LePUtrc-@4Ic#)pvgW7M9hF~jg;kG^<&nucM)4lQfkd?_#P)5&9%&Vs?3 zJ6l?3xG)B@obbrT-QXYA%c^(@zA|2U zTEV}f3&Z6N(+ph*dXa)VoxFK2C1xfUpB*MZqSVF?L2T4Z2dWUz$6lP7{QkH|1BYAU zPTH#FX8VP9iAh{%i8Eb3B{dhyb?_&Q{^mJGVfv>Q&EjzTqdm;WriwF=IB1hhyh5+JD|L z@wyxy#A#fx+K<|He)6NTuplEqlB6IdRQ3^ja8QfuldbOz8=7k>?w=xxPdcgm0uG-1 zF-b?gEFwJ|OTpF8w9y=}#o3*6T4tRwG)=7^OrUd7IPstAkd3&889MM9tg+OzEzei< zp^a8}hX}N%Ca*>cM#kop4sTaijcd4=B9M+0a^E1wWUvRIZk6x zvzq+-1 zSE7~D<#l1pYLF`ZYysNr=3z_NKxNEa^n;t@E_WyEL+tR=>EEwPtNcwQ_5r@m6HQVs7v z?JfQQLYQ2xvo25iysC-478O6mFay3Z(mg6Ce1Uq+cx(M1T#n;EV%bzvGzfBZ7EVs) z|FSujf6-^I|ABKXtjuixyNe;F5mF7~6pK?1M#{YaVdLLLAcOE9G&e9qg9s)g+nnU@ z;vVELC7b&11Hfad^~vk%tNOv$dMU#*XT!UD+Al0tMm0=+4DKgrLYSzbjqdsHJ`h|E zJqktz5GpEUJ}N3MJc2AnoI{Y;Q~*ClfoOjhE>tx5t0vwN6x2wO^#}3!s1hO^D0Mpz zNQ(!E?t7muSl{p8Aa)80c>u1cUNC5#uzL-ra122%LWsZa?6GOCfW*{w*89FR1 z44Q9dHkshmm~3hQ?i!@u26UBJGd_xM1n#=s%%67#^ z7#Ke+eoqQ<_*r7qw*k0)Fpn{$8D$knOYQ(-;9L2pZ4cbD1vdzzTNM!YHvHyJ%)HNJ zky}KuFbfNF114qzvSbL20tk!gClegPnm~e(Xmle6AXUv!0l9oA=O7Iptk2~x#KQVA z@E|^?*EyfM40=5Z%$jbRHT_qFJbq!Gc=h-LGEk?-Fo8X~vwq7|@NS?#1SdD5_HxD> z!-NHh1;0d>48xNjt~e{!e{Tg{dUEjA$%?5`o2>RQ5y;t{K@!a zrSL_&@*d=l>O3gyd_?_>U?O<#!+M?=|?m?!E%WZw8EC0R0!i!I#YaSEbbE zWbY1>z}^gW>iPCV+#tI1hM}TPE|l*oTN07JuKR|OrcOE4r6(jh+0>3z%WVx_`)RL#8>J5*!IAEunkPl@9-86zz2)q#k zwzeF}s`K^V5~R0@V`wsJ1weCsTsKsWUGUYRlajc9O``g`_^o!d5ZAn1?%};Y7>D>6 zD*pSin69hTJ|yDMTIW{<1E-d6_in_-d23ml zFOj{x#W{8O9G8Y}${Jxl^TL<$urN-PXOt)@^+-?v${c0#tOki51qaV!mH3$#DNj?* zwW!|_Z=-#1rhVs^Hw_)X2Sc)tJNCTv0lkUld;heZA1mfvwZC-Rq#aMf+EcWMMJ0(n z4ufv@vD8esDXp!afHMC|wDMe&l^Q;v_5EB{B&<$N-hQK$?LCwaWmZY0%%N#V$tc~%m6o`}ihsNF7F-ty1$tH3h+btjp|bO*B$@Z4$; zVL`LI#Ze)PL=oBb)qH?|Ps;|*<2_B|Z*g8lt52g`buqlsw>+wxqf05Q|Lm8L=Y(gV ze%gKYV@6P$WyPM(ZQ?ySuMT9eIUsUeI5tYKYwP2gHGOty{2m}&pPN2fcc3!M@pzWq zfZL9e9GdvJF57s&E7#dsGDxxCr-ILNw|P*TjV_D8EYPag+0K$fO8I{PWk8z0ZGVsj zv|uW{oWy9@EBUqgCU=Tjg)*NU@B2-5X(|Ayl=@n|hPnOckyg&aJ~JYLNUs7f88Qw5 z9x10WBkkDEw4pm0vq7|L%%0}6hj~Z^s;%LJo(NeXdmoTez;NIjAA*lRidw4owqiee zhwd77(z)HoB#A)c-rE;zX~?E%(|@YAsRy?c1zUn)O%M+UG~V z)V)LjfkJ9)8(+77%2?w>X?apxibf}VU-4JBEsvt(JT(6vE?d5}$`T&yd~p07f*}&e zaeQG|ms6af2G>VBi}TZFMFc)BEQGoV9sfX$^OA}>%zvNsiRSk^wyTD&3R2WH8+6;)as8ty)DyM`EuxQgvHAi6 zconuZIY~6+sVKVR<59UVjAyDc@GosLr<%33?|JeT{M0P{%)3vL;|lKIq$-qDzUHu< zfVh~+O2b7c;@o!y*>+|9>*JxfVkJSU9=j4W~v55{c5vg&Ws0xG-1Q5E57g?|(}^3KSKJtE;IyXUoF8 zBK^V-4SRme1HGCHBT5Vp+H$sw%>#(HFDY6A;UQE`2l;;BmX2r#XGMmBc=0F%?wfP0 zpf6k)%4 zoHij2wRsck{eKo@!+8hmlYF)t`7z%)K#vgsU5e|3BuuM63Hvh#_k$onhj1rttEFU@ z!!%{mN?#h|`77WMZh^9QO`~EW=R3E|O~SycuR0A2&}a@La})*}CO(4U(jDQ~pMz|% zvyBp66xyhgn!Er)Rnsm#w(ypjKWl+?Hr}NbD^Sw$4}Y|h5hjA@d7rYix9jE3G|y^} z4Qy+B;pRr$yiMeB2$kk?JG>Wae*RD$^QD%N`|RN-{Uf8Vt#GG;vx0}->C`=xS4-G! zK;?r++ZhW)X3F2a<6;H|h0Cf55>5fuuwr@zQNBhYH6jr_Xj28aZdG?3jgMCn`4d}> zbm9lM#(#A?eH4QXOCZZK9%IC9iivjy>`XXD2ExyK=c@DFMWEu56<}a}J7pcA<>sK? zhr=c~wGJrC=Fg?1W74J@wpbFJw=2mB=0}OAbUY+XuXBDrBB#YBLy0-+nyk_=^(gzM z{G{&nrywzH9^xUw8!K@tqlK~9J)su02(4=5v412E{b{S3wF>y>OWiCF(%Xv&gq7C@ zr1Zf`$A>|S6iVk#nNsIP__oYVC4e4Q1EkMAKXJ)VF3hkCKI7`y7aMTTD9~@k!0bP= z*y@YYmYC_<6shjb)w|t4JG1l_k~lQ2o%Fh^Vift5%U!j&zkBwDZSKlnpq#kR1n2zC z=zp$Dc@e!<(k$nz_VfuUHIppsX~Q29^`0g#--4U2Qhyvl^u%ut-{dXQ4L9C1PIT%@ z#E}N4j{PziZ*8}v!O)Gk+{(ztiESbtQ3XI~YJTzZ0NXL5f44zo{HH#_^T2-*Y_ zY=!siUVu?EWVb9S!UgRq*sl&8_A9%weI0ypapN#bYB zQ&(sXuX|g`C47O#3iKV zIUT18+3Mi{`$lW*FAKq5-Mmy8pD0#MLbrV(^k;O`Xzl&!TzI3sbIrJCra>xtxJnD& zO~u*so7UHB)vnt_a2*UKsq$bC1$ypbi$YRaQNwrG=U)}aE;|t2rzV3=(0|1ZQ+UHp zNXYx9=+~%WChqNeJSRiWxlP^gLH4W0@fI(+uLF*n92M;%x%`~(TguEdxruz2fP%jY zhx{W(zSvi5u3hj#uRogYZHMFhqF5Ib+rlM`K|M_^bWfj(3qOs)IV~GnSr`?((&Ky8 zWHyPli{3TCv~vbR7IPe4yMGxD5`MgII1lPwY1$Zyt^~(^1ZOX}R67 z3CYu54DM9Ah;XX)0_#Y8@#b>|CDiCxIiEa&&cIQRm|B_2`uwqL1*zgt*c~4|_wn&w z9#Lz9vB5a)Lx-A{u;zH{m(JG*onsy!FIqTG-6icB#l{|2%~X>l!+#1dOFeqjzcnI< z_{lF?8Hzk_iW`nP@OV4$<8X|w8K_ol*^?8n$B}nHacp7nGC+leFg=~ydAZEm8dobQ zHUy{39O)S~8ssN|D)uatBPxu+BW4@@`6p9m1N^*1V0Cd}MnojE{`fX(?FCj+BDTW; zHz`vsJqZ7XFqmboHh=W8-R2=bJp%pyF=V%$s@kR&Gmyc$N5Z+rqa_kHo1v0tJbeqh zJf}yRK*(VgrGdL=S~vQ@>iyxm&-?Ayju<4AA0I2}xTul};0AK)Ki7mAP&>Je-vJUG z&w$!4T*WIJE_ZjI@g-%#8PQEM8!%z@YmeHdoFBv9j;g@$4u5^7JFsn}Yi_BhSBfqV zWv#EMR#(J)-^Q0{&7vW02;UtiFm|B6it6z%R=|yMb$@9WkUE@TU#5v}L$SeeL{cM$ zJcE6D@!rft5AJ17eOHqAE@c9S?jb9!e#wLouHERtg7He-*}F%a7moq>eCzEi4Mnh! z=@BjGFBSXqsej)T>@CMG)((6MGEsetw41LH?p5J&(0>y5n-I9mNZJ0R?Z;;1%k>fx z7u=H)6ol?#bB$aTV0|tfjEv0H8P*uYkaCxhc$<=#v(hq+u+bE!Z|^GR;BK)zo)3>8 zIOJPB*z>y0jLzriTXBszJ-s)D5(;6)`DZMH8~rw&8-K8#RLr4%KFbo^WIXMltY17v z>$$@D-Oo&rn6;`ec0Yh+pJ^3}^ET5|&itaGv|(pa$vqx#ll(y7Fwh!TrL~5|wIx^9 zJBQo#xDToLp?;T_rE4dky*+YESX>Gc;B=$QF*DytZ}=EHHB`8iyPzA(DybVBD&kRw z{%~0`MSq%o@VV4`uywL%m1um|8#I0S9C67$-crna;OHEv|7L+*^gsSyLBPAU(nlwaibgMUK|x@w}5Iuk)5F%@n0nu6A(WliD| zWj{~LL%#sFbm6!IRXFO_wmVchUSo={yojMqnVKJpnw{IPQq@t%pDzlNxf0N5|uO~9Oyt;$$15t8 z0}zW`Da72o@EO=oH7FTSq3C1eoDrP=~I;&+xrx5t94*4Ub#57v)Ri z;18MFqgaimS79~N_!W~^m?z)hY_7$^MSqVZS8KRcdHYQ}5ZkAVAPA;0f~y2Pp`Ax% zAJ#8Eih4D8?pbZ!={AJtGJ4*-x&YMe8h5PLVy_sMERkn@!>6$gvu0aUM|VLQU9&;S z?P3!08>>|5a{_4E4~1~1{;M|+C#AT2FbfxScg`IZxDfYSn8uF2Oz?6~-u_J1qI zo?o{CQgl1N8hK&Syq36K5{7a?YoFbrzfyY~m?v|_`eXLAp+6&E3SP%l-YMaLueocx zzaOtuhfYTF`^y94b+@VVkfpkum4}{He&1w;T$0DO=I8E{milgQ_OBD38}uj<8RAR| zjO+Qgm7kk+A!#2n44R)HEXsXyQ-AEwQ#@4dAGdl$`VP=-i-&@Gpv?y-E~f#_<}5o< zV`w)CGMs`Rk2h`4`1iQCRcUg%H_PhYk0hz4qk|GiMiDl&;)^aQI6+c-SJI*0It}pP z-Nlqpuk&CeJq=Xj-W&yqOh?3tPpSh4kK41y$PSv0m2YtCkq;M2og^WwUVj1I6udJ; zqpn5p!@_-@>gjcv#5=(%hCptb8?@)Kh;A?s#`?QCK&n7^AAWW1#+SmMv+G#mE&boa z@UK|qmm#NKCf15(_ogE1SYC>H@kks?G}KHlrypUB$cOADBY`EIRO9Jjk4Vp~MA8>N z0lOGpGG|K|G8VpXzqXTiN|x14sy@n0Dx;J3{cT1x~X*3CV0K1#ODMi z)bQsM|7s&?w7|ES#6mXFEp)%$INOlGIaFKo%wA9u>n^f#2qX03Gk+_VbF$P>cfulq z>|SKk4zId&soV3D&J8aZ_E&Ecr%z3TMTyjfvB~Tb-CyD-DyKLW9Ts0XEYW9d6OiFW zYWu%4@Q|j;Ka0P-g_!gUvMBL+7?~)#<1bdXiRe)ee4soFUX4~KCFxp3!fQI>JxLE6 zUt(TD?mZXtG0yy@$AAA0%A!g)x+Hf0`3jIl-%{f~6pZWUSLW>cIjFOkRcrmTe5HhT zyMiMy1F7R`5xh#al_lYY;dQrX5$yTZT8~)u{W}9(t;+&Q>@dAWHvS6G!p?kCGm8>Y zO@9*Xh|0j4)T95P!BI;6OKYI&+Sx`E;=S>-(S+)P#_`93OMfrrPg)5~6rGyzh}>|r zqJ{&lwhS_;8ZSRT`$~$HaX|T4LnH-xg**`^+!^;y0B~4fpJam%`2lf$xtD?zQHEwK z&3{;9YS*;$ox(GEQrto!s9Nb$yhbQ56l3{pT|>F}=(6CV=3zU=C1q+-7BNydY(Vg( zebWQCL^z3V>VLBX)*G#lM%$=LO}9HCHPUiBNXqT>F0IBEs6@k`HFWw#ru?1dg)9eY zu0EDoTBeXT&!o0nsSXraaP}vUbl|>CTej^po;|A84kl188UTnhPbrk5%fFi^-S82S zVE{QOSsFS5a9K0v!uj)NQt8+8eB_kd~~IQzq4EIoaOVaOiB7I*0+j z52-(l$aiu4VM=>*(nRsgOzmg3~De7j}ucXe4pnWN%qKdJaEqSt|+@*q(Vb)a6#YT>qNDJAf+Y4e2m>GQsdTVvX>y4n4oJ{eI z$99tRga_+V4{{3=abNStJBqX~L-MZM3V)aNvfrmNeKx(n<`A`tI=!1F7d{H$Bc6a- znvyw1w^1&>y;!d!v{T18H@8@Kdhz(I-!3Znn8)Bpr#A7kTk*38xg0EuP;0EA*GxX< zEp@uqgz$Y!0T*u=9iC;Ogl3IL!h)p<4+`OkDP)jX(xql$) z3XpJ39b1QSM~j#=CMj{5OqdP&uMuJAld>VyR*Xu#9(zx_mCGA5(D=!HXhWZT}OE4uY=df-^>CIle$pcpo9^wbw-A*Ti zCft}iv9ZIJPf+hD$4R|0noFN+%zwEsmwmF0Zi_r*wI6}sL{ixT++@8*`BO-l+=-;p z_H*Qzb|?^Q)3o7Nai?W3`VgqH!9Lh01xsnOl0V0Egpn9K@$);Pv~>J$*kaL7VG1m- zed^HR;aw~ri$atO$3JaleNUWhp`%PEW?W;XHU?D@go@^NQ0P{_W_$UL$&WNQvf0URrkW+lr08;qIjx9tP~R zz4+qymi9rAl)Jc`JhOqMS2Bv_E50i@^_}}wg|HScy4eybcoiH2?SJuQxo7YyBiFbs zx3l6zRGXSXghTb_TG1Ln*#yl|#~pkm5pNq4Y$VdUhVv4>1#nQt3vm#2d_o*NgE-Vx z4C`iIP?VgVnNE0uu8|&A`9Y$arqHYd_`KTGs{d7G-wGMc{LR9pg;LC(Ld}XeG=u~> z|1f>5DmVFBk_XWSwr@uev+P*NvO>YyR)qer9;TP@i_P|$XqpT@1*^<~> zYiI%}HqLtX{1`Kw7xHUz-q}yzs?U~Nu+9%&IIegryS(HZe|yfdyY0ry?~8g?t6a#Tvd1UsV{TjWJi+^ZfO%vrx zPo`TY@gl2I=#Q)E*PD)h^OrwIgK4gQc7JT|Q5VxqdgnaQy=>-VeT_l^kEYXO%PQ0a|YuJGY{)ykysDdnu4LmdM3dK7eJpvA>$l<+$tsr!}z{KH9-LtdzXw zuR9Ch;xZduGSS*A>M%FS9!Chj<+9Sx&an+&WS#2@x$cgT;6QLwI!uVZSnrmSaDQh| zO4%#q8QH?hkHS*Y)F{N&zGF#3IGoI%e7}5SY&@a>J4>hXnLK~(zw*XV8%M? z%`keNykVQFviK|Bl=-woKDZviw7U*J^yB*E$CVmEPFC#IHjL(55r3xO!|iE_^D%1@ zeKwH~tqZ;z>}fpg7Fp3@CkJpMRDV;y^6mAiozjO|8d$%T8Q3sbu9=7tO2Whc;0zCA z-eA_~%1C9mLH zIHvc0Uw|H~3EHy3(ty+<#2N2k9xT~16i+MYwtjRUnRXyNCxuL*gQWFkw9z-~;A~}|&g7RQd3us(FMmWv!UhSYU*$sF zl&E!wUSyjOBpuXGu_zG=+r9*MwF?Jk4qK6&#&(eqGfGn8js~KyaE+R~8AUF^pl`Z! z-ySR(1(vRb(9^(T5}VF0Yt58QH+E-=9Zx>}$1N-QnCy`zv#hQZM?t6^=4KtgqSse1) zX8aHRugleQ-vEo^m#q2QSwGOEmrbGgn}d43>w>z36Gq2kH0!BIi?(PhR(Mxslh-|7 z6yWPZ%(J__-0!QzItAA=zl+-o(y`1kMFGZhAVe# zV6SB|^Nj`PhI^EP<8~ae-&okaK5+SB@R;L%5~_$g)!ZyL zu;qgyXV#}mHH1UJCpM?5p?%w1hV4N`&3$(LNZa|jnI`|uq!iFo`bUBPebKjHnNNSf zlvt=^MC=RIGsq?;q0eE)EbF71C7|<=0}YwliM0xO zFT@aRCKS=rFnC)(Wz5nomV*E#OESCJMnv`;*1|?Pz48qSN5gOJ@edxQo+UmcF5dYu zI1Adzm4CYz)$VnShu6$Tc%>;4AWMmDiGkr|0&&U>)%UEA$Wk)@? zRI=WM#gZd07Aj7W_32>`3N<=mK4)nPB-M|$E7axkQCVFLJWKu=k#;|w8iM!BW2PE8 z&!?9ShU|5J`IGiM!4&jFoABOJ!8w-!NN2f5B9&FHX6a6NPOt3?9=fk{nVL^*S)kcJ_3;C}yBA##;H4`;@_%e3 zhq@RIzYgx5>TT|B)D`FUjN~2y;0?ZUz1y81aNm3tC)W>@Dyj&Z{>J1=B_K)wN;?jD zKfE)YfL(1>W%z5ItMp?y<`5#6*7K;YVv|ckJ`C#4>@}YCE^z5Dir9%>X4QAjJ#)I2 z%cUZRKMP{98@axcWQ6M)su8>*?tiYLvCiK*6KocdzZP+9ijua>-cNr`)XRU$o_zm? zfY!f_MSs+fOOz$EU6_I@a%E#!l{issDM3G5P?5y_<|Q9WH5+OzBd36j=Bfav>NGOK zG+fG{WW(qX<5`!F#h>r*t2(fioN%3mp5 zTpE^q61%OY#PhheeN7^opMPrjH7N1VRzCeQ0xDR>f!eVoHFx_Pnj_2ksbA3NfCVs7yAuN;&+5 zF5R3=M3GsU`U@z_T)g;1*(_mZYeO`$Yq!>vn|3!dAC>X^=tZ){dw=GM-A26D!FrO& zdq%65WLo58T_-^>7t5R6h$DT3MNuh&Q&XtDB}slLDxtHvOsa{BE3@F-yA`@!e1%=k--(YSwCYsvV6J5%V+j zoiRkRMJK)>99iqS8GllJr1EF=#z&7wEjQ-ms z9Fm9zgWa&6IVZ5S2peC$!oyN{wS8Z{h-E28<=ZpzGOaZZR`^;t@CMuJ}ub4y3n5ZButJzQ*uK$_5$z3@-u?v7Kon(i0Xn)zj21L`F0YXwUrgw37?5|}| zTO*D>e}=Xo_ra_PzI(VYc0|ScGvZgl2Xr-mr&LzmWhAtQx%tWGlWb(RMzncs=3$?> z0RsNlYkW>r{l$LrmV5Z-RRckxEuR~wm3Xd8DgCkqxY!`V*5iXlJ`q=`KUipIS6l~O zYi4InDSwW>v=2?Hr+J@>)zqM<|By;1*gi;8t0mWUS)l_c*@eESr~*y2@O&tlj^!as zS8;h$h0JiQr84V~lj^ZVx_L>IjNsfvFi2^@eO=<$TiZUUPS2Uo_(sK1yUsAs{_wcg zV~u&rTWoeOm2j(T7(=1|#Iamke#t-B#w5%;nt!4cg61_-Gvv&Qy*op04J0iyE3mC> zxssw;{E>SuUD0_gp`-TwMRC-3Rd|p2#&Ng-jTyh}wMlyP(lZJ%ttQMJs7!48DA5_q zsqQ$x&ia~KZ~A*d6vsSnuMbt|-=I4Oq~%12Fdw;zSJ>Yhj3~Yq9g#9yaRl;^Ya>w! z-+!#r?^n?p`lCyk`P2n)GHK=nlRCilVv_J^(b;N#bFwPV>?z(aw{iKB<<+uxp1JLA zEQnrq$Wmh7dFc)wM@FZ32+L4V!+U-z*MB@f^lM?`3DmN=hinUphvTAO7X_(X=o2zg z_-S#CrV_sx3G+Hj4c}`Y#6suj{)B|xpPw5}iE79}X~}po0?K}ho?myF9W{MTOyQ&P z*cW3tlJ~6DB*P9^Ry!p-fcI|ESoEqj?-zaR-8+KoP=bqS-#RANcD*-}cG;{OEq`86 z=6pbNvo6LOzvqFtIdq*=nLfK$dH-P`WL>MnhK;8F!$j=aMf? z!fLrW66Ymf9)t_XGjR?Mr&Mg%G}QIn!)Yebp$re`E?cc#(Dj}1WYACFPs*v59K64A zh>7A3w-;PcRu^QTAmc+9V4FjtkAJ2?6c#KsJUJXIz# zw%I`5b_Q?iMHIh&oX-=6FjcdU+)@AP>Q$ll|nsb zNz(qRzrv7G@ou^DyQBPjV~HkqSA6ruuR;}wQo(HAZI7QiAVOP5rQBOeaeut#v~GA? z6Ug!&lZh$!rRC97-;Q4SqX>Se*EK)CERMX4Fehp7AL!+$YZo>vvf^gS4b=x3A1Tjv zZ-yTqQRgFsjA#gdL4CoPnSzPQq0L3y5&ibN1tUU}k-Tb76%lZT@Rw?OJHwH_yFCFd zR5*O!)R<~6ASwl7*IK6DQhx_-A?G~jB$eW+LC~%=o?)-cz1kFykAzA43}&zv?VOkb zs*nIGx$3krYbw!h^>mtZl<9;_ z?2LfocDBxRO!SQ001;Ug6(&XiBO?nvBO^0B8JUWOvo-L)ba*l~prez8oqsL&9}*&t zKtpE`P1MjCBq(cV3y^lP1~9PznAo|QIJg-Z0nChyT>llcbL0ky8oFAT0A%R_(ss5$ zCwMXuJ9`gD3o~^k>M{hpfZcu znuyrh*Z^&vo#6k9Pt?K@Xbh^m2g5(jwX(Hyv-SEfGPSTZG5sqI6Bm01Ra*-O7oe2r zKQbT^{BN2W&>6tS$bZPl$-)c(Isky~#^wxvIZ*Mi2mZ}u`il(8!N<$q&K_V2N(1O) zVG0EOgZFYWbOi#O9bJGvUVk$F7r`?z0Zc56odHHbGYebz-_}87py_`wsQ-=@?f`8@ z(D*R{82|eF_nR(g!c6RJtv!B=|J`B+F;O)!B}JNlQvR1IEPrh04)CI51<*0GumIRt zH~{Qi>;RwtwW45X@lO~8w+cXe*5UB z0a-iHCfNR8QGa#de->93Xky`F^MAQg&W4~}5VAG1{Zu;9RNW#>@^|ukWzu0yzj(>kBfJDrGI|1>{{(A5M{}cg5YW_QJ zP<_lj?9G9;e@K967JoocQ!M|0phjB#0YRnsodi25XY0Qf<2N5vxIZ!iT|kE4u2?{x zY+Y=O{<>Ude?$N}#SC`8V+5H1J*@v=gYvTf%?6pY2R$!s|EH6zO#e{-w~wr#WI$tQ zVSo3#GpwMR*;~8(5i{uhfx+Q-kf4G&xY#)ZO^p8N7S}(-|25CV1QPzE*i4`Ve;Z~4 zDLDacEdI~vfC}nlZRlkFhZ-o#-$p_AnZeoI5%@>rK`A@C+5Mpavf=W3SV3O@eqnGj zwsZWmZlGSd{sBSZxc#vzAfxVoK#*6DKYt*o=AOS}23hh1I{qhu|G9j|E{>q0JOBM~ z0-eSG;=kWDfIxSkG5qS1oiR_aWnFN`eT@*l8{NSa-#poYdMXv2*Q#Tu%Of&O5><6( z;Fja9P||20%KDxd)dH*_Tfw`f$#NZBIFS|d(eK>`B;4x<%ho1BmktyUtJ!4`p3COwqE(}G z0*V*N@{F<;aY&$@={~?xqg}bbU-)%9kCrq2MkF0i1MhPl&GOYtYnwUdVbOD=LWS9> z2bUCA3+DsmFSLnSaxdZIWNGYWuYZ!Fs4c$bY(^@2u&s$fBJc5T;tOu=Pf}>ujMk2; zToMzcKJE1k0UG^?aG3|n2KLl-_Gie;I5ehiZsHR8@-0OJdWR!naChO3G$yjHu`qHT zUWYrYP`@zU}d9)eRLM7v_ZxCV*q%i%ovj9-ku5jg~^_V?AEHyG4rHhfaQvV{UI{ z+8i#YU71OSCHy=(c2h0hCt#+OCR19k`*|{sS9x9`u%+kieQd>7zJFh3yV?^3{RykO zH6MLbC$#2!wN^aF+()XT>cVP=1Jubywd3bcz%t0u8V}kQc}Tbj+Cvn49(=mux4Qdh z4Sy|J((AuWMdyASmn3T3usw{{JG~!riyfVpZJwugw`p0#I@GL6!I0{hTHAe;)JC-ihp+UB9sAG&!xE>_KKa+ ztc=Fsl4%QztXD4D=SXgvo&Cw_*#}w79oo(_bE9L)-wL7{G6l?krbV#`5tA#B&Dx7 zm#-otlWp=xhkqXpepBJ4B}XsWnT6n63f36K;P&ow%NoKr&rcQr1mhkposRj9w=3QxpU>lbPGy5pz!- zD??FkP76!7VEL|24TtBNq37u=6Tu19=Vtotw5uNhk$+mGczPHffI^5M(Ic z%k0i0QSj%WW{Pbq$kB4k9(zS7vq&&2Aq%qWDD9^1u!QkzOU`iaBL2i1HbBjqCuKaFy$w4}F*Ilva1y*-`Hp1|O*xc2&=ZN$H+Mn6Q zCcD;b6h`Al8xFL|lDG5#`GlHd&cPixIXT-qtpSOfcQ6hvlZ4H~wM(*z5M4ie&3~Rw z7EBl*A?RW3E_|s6I+M|M+PdD4bptW%@5dYAnJ(*m?B4s!fSpq&fA=@5B_X5P64 z;i}t@&~b0<5}d41SCQ&S1)%4iIDb^_X7q`Hc+jpij688q`K#wp-f(|`7(Eqdfl#Ki z0Zq!3-RbISB5YM9l7EmVhQT4R_p4u}A$8TH$&o5T925){y|Wa7xkLQ&Yd9e_BV?|_ zrGHzke>MM6upH*FD%>E;5Yb5NHplw`e=d3FCT$k)=qolyM#vwn_CqVLPk$?%Fk4CL zsRRz9p9VWSV!YNb4C*ivMoioi@x7OWktC$wJQ=wi;V!2?{<>Q?V<27P0kVaq5-ZDDT9ByPaes+t<@(0IZD5D%&^5^rSh(YRg6zJV9IG7SooUKNv|J(3 zqj62|G9v75Dq$q{Oz)=7^AwV1N81C3{Z;srm6c4R7YvsvteM#}Ex7fGcR6_nzW*E! zvh0WN%_|G|1&y7#~Ci|OU%E2g_Auz&hTjbu)q<>8@MWr7Vsc#OI zzrvKPzNxJvmZr+NK+|x&eS6Q!fg0%{@t$(F?{#YnsU!fYuP1_}(sOJV*-pMsKhe9w zSnHL*Q@HRjNU&MUUx;X<>tS2aumI?ue1LBx5O>5+GKHB0{x%Au*%R{pGII(0^NC84 znQ((O6#8m3m+Fi7seg2}012A5y>1`Ew|8UqQ|3`Cy}468UrMe+RUtV2rxz1E^Nu#V zK7|U@`#(Y?U_Wyc%0%*1{d&w(e zqy{6nXD8DZDLW}44UCDo@2l@z}1F zd*g=h+UG-~SbxKK3FV&h*!UzPeL{D24AUkRg2@wBWYEVSV^YwQJnjApy4Yx)qm9?C zSW4jCuSw6xNo`V)w234m0vTBe0k?Zb!a37ZBhSm6-s@`;)7hIF-*tG}BoX0lhjyTi znZviL-H9}&pfPfphy}Q}F?Uc~lMhg^oIeuwZ(|9NwSUguC7A_BD0c(3J=1f5lVBk} zfUzxes+333b3{l>y2lXM;DK}bV0PDEo-T!Pf<{4bk%Mp+?hVF68wQSRXylGPM+8X7 zQs<}8XtB7l-&*zgQDFm+n3PYIP2T+k!#U6-y$ms+D(tKLH9LT_%>6C`>#{ouRTtr2 z2~BrKTz{%c#mfCE!_v$sTQb1}mY$LuzIXR~c_smU)C@!lS)si{ciB&VEWZkVy%SG& z+HYQZUnY%p9W!>>?W&qX8(V+njcispOD3qSi@Z!P1Cr!P$JSn-gn$T!e%?a&G{%ipC>vGVCEM~yVoaiE|1JB5v=Xd zV}I*-jTyLXylG>G;}bO&|0FwUW$6u%eGcL1(^+)14Gfi&CTcu=jhwzod&w2Aw5q5> zsDF3UC2!fC(ur5K_3eaZeD!Ztb5=m8dpPKxmcN?Zm`dU-%dOU-(;k<{b z_XXPIqx2^xECF=ch7kdDlEDn4;t9oGWPgJ1U9G0Z%`@{kjt!mF2)t(2zR}-P;@LE- zWv2N8ln<_T&rIM2!wdcOVb~TWowfs?eyw8;oig0)wna`@sS#|r9GdO>CBEcEE?uJd zP_SAj%_JTOK2&$>%S&ywa^Pl6GkC@6L3w)6nK(}3xFeb3=XFjHJ)&_)Z_O@U-+u=$ z&-dIlC})-KQRLv^dwSuvo*6ZMoj0~pFoN|R3IJPyXUwbZ>%T9W^u*tjny(}dMp6lC ziBu{hou~au7+7-7kb5i)R(QS}KrWUF&DmR@HvB9L=cam>dCr=$@@;@NbK9aQOw(Yi zl^VFBt4R~>@KZLvkh(d`w++9?bAP>!che(4^-yF+Ff>K8AQV4GRJUz>%f=-ubc+4S zNB#s?j9$g4Q44jk)i)hgpCv*qzu^)$7rFtTRq2Ez_5)U7-Av=@)ebT;QmI|2bV`hR zFL^g+tGBuq}+l)Y=1HsS3+tM zS>6d~!c>ow2wkz9`-*G8ZBV<(pHmG{xH-U0$3jrl+0J$ay*daO&R&C%n2rwDB>r&*-u$! zU?wb@YcSo_^HBUMnR(ZsSAXR2o_Ct^`wzdzUN(sygkT^iihi8olpX>;kv^PB3XOHS z3W*n?1$&LYtD~Cy8diQNEO?wLbn;P7V3~Q)mKj5udwX7u-0a2ByehN6jhVgvRXMYCa&QtQ?UlfMY zttVn{RlKNm7*!A^3CTu;za8YtQ$Mkf_m6i}Y>tK{U}&4*G!K zFaXW5gLOG!Q4sgRq^m5YH}S}|nhm2K;I~+;N!26ZkX=ktNZZ}4aEmXH9hS^@5`)@ zkbl+TKcwveM(#>(f|c2ku^u80uYiS@z1_qt;Qp|}nkr@}sZh}0plf}wRPs~|Q>VfM z!*j}~Axtqd7R+*r+8180G>Y_ToD-Syn5l%8kiE7_?!WID2Y)Ts9J2S?^-{ zb2lIUnnDUr4l2KWS6~#~!LsZ+jS7A&<}7`_jwZV)PY7*z_QQ;0{%(6IJGtacq6pWL zjpIA-eh$Yvw0|EG4`ke7H`0!;O}v|wl9_brK}7y_ov9E2&~(zkq2Tfb=z&X2(g#>iK5*&unT@>$-Pw>pthmbmMCp75?){ zgl3nXWVEkw*Qrge6A7fy{~FjTuxgTv{$j%;Qw0we8>cwbIX$RIL3YKc&nQMo!_R*N zs@P-4JP^tuW8_oO@Zdw`!ol@>lDLa*H;%A((N8OgkPOI43lal!IeHojIIxa467q3W zXh;w`qRO%B`APA*@DJr-wgy-mcxQ@B2V?=+d8%H;2|TY?nOrOj(*#%*TtF9Se;=pKHvbfj*8_w=zA1g8=D6xO0b+ZBI5CNd+qsIBlF5` zqhxyU4yeLKa47`$4z4W$JRZ~IdIux?D6KVXWOga0??WgwvGSB+_&m9NjW7-L;%4-V z%EnYV*X6_DOT-?JtUZ9x%*x+) z8Z(x2IGjG889X}`HUUru&MtWebQSL+RGApDI#(TNrIEN|ELrcL#%&dl}=r)L36(fqe8XB~G-`cgK5>@gn zS>x(i{Kbtl#!ID5WZY=U2EHD2;a9=yb*z)&fFWbuzN3Oh(rvb z((s#>NPdqvm|mD^Ll$7H`hze~`$vzVDl<+(%I?z1hV!C8KO9X1vxlk~Q!7Jd;%8TH z1|oGx5$ci0e?dSTa@cVDEanfRi}sWsI>+&&>~&E%W-3l0UfTSe5V3u4-@U0L6E<5z zK?NQl%2OU!;(#pFl!-Bhvt{suUERif^o}~JC3IlIqrsn|H%6f1-o5wm-q0Nh^0=O( zy~zSsUbT>xy=OZ^$`K1SiHFELl~o(fNVqo1hZK~l?+c|W1#0G(6k^|1oQ4U|8@`)#lR{ys;KlFJu z_0c2a4C5WP{S~X2Wy$vgxf%_|_hPNmm#DnC8x6Ub(1!-^0P#(1)AtClz=GAy=xke6 zf%q=M+mY@-_a}Zf;>eZcY6xYO&d>>p(<3HTMza=sNd~a1RFSwyU;XhVq<~pp;wMlB z!2p);K!^A7pYTcAUMORfXe%AH`aEXakPwwLY^y?ug5nNbua!?exfGqnea#1XgO*%< zEp~MX8q8&LR7EzkdY&Y8qZ|qLT4X6P22|l8R4t6?B^}CzmLvDEwY_CX2VUs+%Moqo zc>Z?KrVtS5wzwqyO>N2U6AGc+-1w$dTL#qmR+<@Cpxac6Rk zG6zZ;@7zL9^I;Np3kQ9vZXHXWUIUE`p$%K^lJO7{Z)I>*oBag2aFsF*6Unvzp-f?Q zEqC{m6B3N!H>xo1o`e|j?$W&_9E>#TlvmMi7yuZDF!FogPt1s_d`+RvQITV!HN|!$ z6~k2Hhm@@lnt>E(Z=pJO8Y8*C@nXMBb2*AL&r~_2@=G&IuGSRDGnh2unx%u72D^HQ zd(CCN55I6a`qx0ne4iay zeE~;Lt@Jz5^1iBw7hjl37W?Se##45>cpks9aq&+XBdI;l=MDE*Nx?E*ATk9>;|cn% z_vRYWSFKFJR1~#q7~%W_oV)oOllF@}2@?h{2|t3O8|uMhx(6&bFqCyb&>f?OF- zdWTX$M(j|UnNOVB?;Z+O90QC>J`nbnCeeb zu-Ni_y<@^sQnmB4#y_6-P11b_fwUdY!@RoIm>(I{z|X_Jo?Z^$tj-uueb>*rU{}H1 z8y1yoXouQm&)XL(7FE@HS2zy4ct{+&U*F7%%I}{;cX;~?yQrtSiMKbd}S?s_7!9VR-s$7SJJ6DRECNETi%qx#Pfoc7;WHwv2c6ZY z&!!%$Yy>2CFCcTLlik85`ViRpYGMgsmo&5$oxf#MQ1|avrqe!k4jyfqEo`#=Z{YJ? z`g(1-B2uU8?1?n>*S~G6tnBfvFYWkv?PV^q47>}oLGgi#e$lP{sgQ)IR$$Ans&)P$ z({);Lbirx^-4Kr`dknb2{qUJR#ii8YOt8rFsYCq3d$omNlv+AX*MvEGXv4G$`_T%= zuNGRY8zDV>z(OALpQ(a;a1UWa`;3WHMt>ax?ffbTvA@RU-bQdJnHv&0d1KCJKYXCx zME^V3k8b{Z`fBQpM$&{Q3P=o>L&C$#`3hGLDa_~(?75X9s!;n!a83BV<9>=bth5S(S+eRw@B4Q|so}gTY80ESGviBHjsa99M7Uo)Y0kr5*Aa>Z%l-rv3H^9@&y%ds3A^W;(080q=sdLM_DDb3#pf#I_J=wY1howJYED+_TS$m zdjZNgHNzz0rBXW;%RA}#Oh{F7W4kCn3!v*SD9f|s)P^aUI(rHhktN#6FMK2CJy_W&II$f8Rq3`;*!vbOs;&B z2pj5ujzZn;$md0}&K{nuDx>y4u5tZ43OkZAq5ef8P{8Ck3Ph<&ZzIz|%ZylGt2)k@ z?rdC3o{6Eh#NjpDOHz4~v$B}iF`*0T|8$i*vAtEdj-u+HkzdBmk@Goh)eT+{sa;Jh z+aC>vjDMR{5?1`7Z;($pnxy{RbRWSTAw#8_*!Nzm`M;nH%RcC6S|Z!0gp2q#=8s47BBx!X5eM07xGI%s)OL`ny#5#sYGC71a5%Bu_F#M&N*Il`@_p^Nx5^`y{cu%Pjz`Y zPCS+F32?3F@2)~s<`UZ~(#NDgGc4dND_4N6d0VL3pj2sc45cvyKx;^r!d8X$i)8;0 zc>^LZ89YDDJGxoPthQ)yDomnHd3-Pq3|2gUQw8f^DS89y$Zez8zXXzJ}U%sQDj)s}<~!K4#g+U!UTX&JP5h8mZs)sF05@k18r4r$CuSe-h` z3cfKkj7QJ@ zGezwvxv|Y})Xd{)alHv$97(G}J#s*4{EBg8ru0MK7O6+s=K49&lDlGQgYtO~kPgSn z%ml+|`gnfxhQ=GQ$GR^{aS&OvKR~5y8`9$MOubnx}9KzP6Ex zE7rO<#6fZWwcyw9vi3gKYDqc;u8m|Q7=IA6J1B=yAP;b)t9+x^Nk z^DiUo*fIQk3JIwf9+wwK7sU&Hce z%J#*F5{MOCWw#YUibZfuj)VTIfoO*zFe3@R%uF{#$w;s%Ch#(Ncn03U+Q7`Ieg#*W zk8W|C_!NXAp@r8N-Y-m%p`=194ZSSvoAo{ zB>@?=2hCtUG;6*b$dCq9@*ZZeXybFy=Z-+YbD&X?qWO~VOAIk@&*0)Rv@qqwr7|nk z@@Vzy^89DkxYZjhdWnxZywy|@HKMBOc;rlMTo|AJ=a zP2Y_-reV|U-nq$FLr}J?nZ!t)X@P|6JcBsO^ED6Px>ntJ-W^(vm7ot3y|i+5S~{WD zd_LHc!2oORca6o0kVBmCHQr20Yqp|#2NZ@xVX@A&NH7@0ZJ!BLUm1rfYik!RA{-Z?KN0>9c|BFI{ zpe^#u!>L#qP7apqS}4(^J19gTp)IeffwkiS(ia`!obZcIzsMa*s;mvkqpP2;=($L< z0G4$r+JkT+@R+ca2z(+lzWQ59H|wrg_g>M_b9IXpaz!1mZFh@J6_*4~XCdOUkS+fH z1|nnzm-kOwx+j$DJYp`1iBh#Ptt`_-!ypgfSut=g*p@YvF9L>`>r0Hd>O5yiug>lD zanTIWDsi7B5WrbD@0Y#2k&PcYMsFDOrBZ9?=hqlnmzg~hBAke>Z5$swg;qpI=shv- zcM~2+Df)qaMu-nmJH($~wd*77=dbZll$PtKpNbxJsH{_2&KZ~Uew6fKsSsS|Md=Xt zN`aNj8#hcQYXaQKzbWbEQTsP;%Zxc9c&jdQ+I{A2>E$CoLw=U!q7;x(J@jgUw@B?k zGN>dSZUkGLKe-!;@|7>#i92%rw^Y&T=q((gyTc6dgJOH$co>IsQ$O29nFCgYxcELlGX1v1p@v9Fz(Cl?G46ZG_%$khEkg|KMXRv6&xU9R$=O05j%EZB>MtI`;7 zmU<6dd_U&ig<+7&U*;8J9!clb^ja6Zpg%diJ9vC;CasF=wWe2~FxSNPMG+oqQ#wS- z`cv3xrpW#2s@iQapU=rTG{DH?g5? zn{a9A{F}%SKlJHROe-yJh)~XOgV|D$(`?CvM`=x z>zKW_^~V!x+$DCLr4nv(4rR|*ka9zST)GeiC~K*Bdfq8#OCS3$Nvo6XD(9;5k`@5` z2mLRQ(KXk~6fsENQTY~8aLJ5}=9R^l(rMNIvNhLSVsWmO6xzNg;1SWl(*Sh?`S< z_8Xet52-l)Kq__46px$0lJ#g^MR1W+)@Hc{LNHr_KD_YUJZmhCo2I*Jdo>Bh})<@EvZlPY^=|}{!!-?%x zXLD(8ZD=La0;R075v2Qu*ahlWO9?F!X5fAGQPEj%W3QshnQ~OYi%vh_i~gz-w9qGA zb-90JXW@5mo7pM$DKJ+gB8FP7UqrANVkm!Akb>Chkgtz>&Jd3#QbGa~1+ z6wrNU>bwlQh8Rnuira`$Vup<2*CPe6+b-JY8n4PIkI>c#nhcbGwP z4TBLQmvo(h_gPC;!M0|JGRGX0taj4dAI=qxhF9L@UTx|{;WnF_fozyi!P>GjE}q`2 z4j8qL?~V+N87J6hehgbJq>s2vlp0L8smH|GZ>lF$Y96bEtrG->MzrZo4?ouP%(bd9 zEYUg;K9=&#tUm&R2Dj1v4GP!1A4Q#_nc7a%PS)V}@)~qB_l!61;RWP{Q}{ER1a+}i zqSO~9SFck$rCJ1y==^)fKgRB%As&UMf;(TUGtzp-Z9nU#LJqg#`>dUGh4r%^EKXfcv;jhJCay< z?g076=1Pg^r^=9FX>%gPOB`{ZN?PDxBi3Q?>Xq_`fo~XCgPe;Xj(YAuZ(W&uCEQ*Z zu7x;p?J)mRZ9+4FC2O%06%Q+yOn+3AO-=ffM;xY5j0~Yraa_}nizWUvsha6eKFBs?JRzmM z)-Qchi#8vyvupnO(*A%{VY(IDjlJieAfD&IvO_G4=W&f6%>vDM*>pW$~8nS0oS zqn}c7nD2?0B&iu7#%CQL>Uz;3Y~VgL135(}f=PhdC$I-IBz{L}Zr59_fKuk^GsmML z05zT~ha0m`nh*jIiXE5or`K=FR0nL6(}T{2XjNBR z3~OIK%SAK7%16PJ`{-8W&n-o|XQ}gY5A7rV`OE1sBb1mUN*Q1LOfSA5GR37n_#UXK z={K6TP(-`a5dblRlyt!Ub&zhFuW4p7k@`LqLbK~U$5~gNfrG$h=T>e7y><+LHrzHZ z(n}58{mq@GOrKlAD|~&~%lR^Z-cAB*|4F;B7Wj!-LC>0DC0DWO`g>qEJfzJ8 zs}5tA;QkwL1VCIucrE(ofPw7^wFY(0`Rmmju%?^bTlQhW=YYGq+&M<6eb}#O~wI) zoch}4b5mxT<_2VF>oQ97{XlJ2>jmtu<|b~OwJyy{(1IO9;XqKa;xgL^=M)D z5*XC9wgijw7i7aIcNX&Uyd~@bqXiad8Xwa5NI{5Mhs9yazwN=gTzSgk?szc4oBa5H zb-0+mAeM5aam(XgZ1V3?{MQk1!bd;mH`6$2GpbJ!P=sHQBp$plpCcpCE(L&eXqAt= z!YYOPJ{@$@uGo${S>sT#18x~!XY(@>!PO*#vx#2_ICWkH6!(}P^D<6Pm%34^{Y7l! zYJKsTzpmY7P7tN<0GgQ_bWBo{K_$~$_$tDP*^(21FQPm$mhJ0_yK*E-;CeCWSUAc-ciGjHf1rj3OD+Ff4X%_;k5%xIo-3$$PL{A zm3J9UE+^j3omIAdv10}egKgn4PK;sDl*a0hoJB@l}N}W{X8x zE7a}f!~*94eQs5!(-@$!%-u%D#02dZe(`r!OmV6pc<6oz^U|WGq4Jt%LFmJ6x6UN> zw$2W5tb!{8whwabs8rt4Jhb1V^r3de$l1V+0kgmWqfRt%M?@ap-p)vUv>`Ki+_GD& zF&WKwztS}iz84{%v|cFtX!R3fdYv!hHmRPeGNj=W-T49a5sKuNv=|eXyoFT0CgZ8%_HQh4y+W;ub=bIliB!^p9KjA)Nb#yrc@D_O^pw z(av$^rx7c8W|(mx{Z2aN3ch^Ryc_E;Vc9&#ExtpNvdg})%I2pLpUKTkz3|+d2vJk} z9Rv)V&*dZA&SS;GSs%1Xc$ar;(esfq!m@$Eyo=H7Vt(MyP6=4X5Z#lz$QGm-Ie%-C zpCwTtvxh}1N5^L7YOkdokpOxrI=`oX8=s8EkWV;fJsu^2ZGTV3Bi&PVER|&pROP<|e?JWHbB&$+%I)eXRyDL-b$WcQl^mYO5qcy!S|e<5}X822g6$`4cP_drG9H zcYOM1KD;hO?!nC~AMLP!{onDF*{N^Wh}l>Wa%pA?TA%NX;r+qCpL#{Z?o8|ghtbSz z8lVr0m)*%*UJ4iRWV-8FtLhZuZrJ7Y4}7Zz8;St6sL)%hAK39`otxLQ{anFlCNdWY1HN`?p7kaZ4 zetH6VY5t3!1nMF*OeBko#e-4B&xw&c6ZQ4h`4gd6rWr|F;B2N=>8CSuayTl}XGElz z^1+B@o}y5+hx&W#wzwj47HfrJqwHem8Uo-Te7UhnYq&I@lP_Us(LATP&-7KUH9@T% zFO9TEkLhi!J`b1fHaCQsXQOI&iLVd%8_{6%3?DRb3*@GE=%^Gz?fU5G_Ip^&RuRF5QD?wN z`fIBHt|)Rf1FXU~Octo{%RQ$c4p!wa4f;Z_@qfEeu?hz72hTf$E-BACvW(*q($7cw zi>fm>wXxq25De0K;!O52Xm#=r&Fik?_+XaLEqyhtUh&6)s!j z!Qo$>C4bI8N9u6(3=KcUDzCE8943qolu~yke*PANj!nwPKp#evj{1C|X6E*@3T<()=pIED0NvJ~vJdkOBL zw!8vXotj_9MKA1bsqG8v*>HQDGF*S{T(AJxoeQGX4b+bHSLmh!L0$0g69TIG!%659 z9vtxu_T&B+WHK?#!Xs!&#wb$w8eg2wstz`nL&?M2d!`Z3gPSK4t79+Vfo(3Imaz_| zzL`({i~;a{nr7~9K*p!=nVT{buBk4ZKbLB@XPqImF6*Pz<#=4y`!cPI^c11Xpsppi zA;wjc(-A1ceNj*@8>Q_e?mGh)q1siom7Z(*j5mHF*nyqk0e7WwDNWzFz9|o=6 z4E$2}`r=dH!UvZrtr+=G`JL@#ZT{bK^)##I^06n&)ii;neeZ#b11j{-7N<|fmHl<6IO{CLB)zkl~VSy z_rR2|ShD$7|6@VMC+i2+nTki&sL*U~i&)^8&dxy~qC!|WXLBiXpHbb?f24PchL?G( zyxU=TzX!0lW-smQU(D=lX#?en{3FG~Iu~hSoatASJQ?UV9!sJlE#<1KTnlP}wt4j1hsN3#cW-$D= zv2-c7Z(*~(Pt(!WR3^0}yts+dyYChHW0fPA-$YVOHFhAJNz^I^z2&=GPpFHTv-AIQ; z9ESs=z3nN=n(& z&~PDrI``egD-T<|0CRVBCIHoiYpY;I((F8=ZN+6{Huj;V*wkJ^m?y(0g+U2RlSsdG zm47Dz?_(DZ$2ZkInwr!r?k+WnY_QyoZ%__=#PVz1!ySV_qU~p6-bIpTe`z#3@Kelf zPmI)t#9BDDr ziK%XGa!xoxbeWTdq5U*569rayfuHPIL}As@VN5WX-m-cwXX7?h?Lw=W{rtz(@ZmPC z7Q8KK8jm0$aB=)kR5u^DF4W^b)^%uBdD;O6>Ebu`?x z9dh7bR;(61k{LXy#stBVRe*2Wi7Pej&DM!WT0HD+{?Hf1!EP8~+P!Zw?{H+0(y$D| z4TC~Mu1->2wh2a7&QFJS#W@L74Q%OS@M&cayGh=BoaN!@Vu(H4(l+ek^nJM+-UZS~ z%X@EoBK*7w+;!E5?XS5#AkK1scfB#KrLS zruMqHy~nYxW6qy=WE%c4Ms(+ap}(oEd1N-TOaZnw#|_&vsiRM=tKHXdtl(ie&gz6cL1V zB-e?Bwt|M2QqE3v0ONnr>$k*(mt!9@j)QDLp3?ZbUDe|{`TNKBikcQu&t!!W(5+a} zlJ6p{ejd8tN;HzPw@s5Xa;%OpE&0T{ZffRPA69IFQ+bmtb^-RQn70By&Z zQvx(12%%PfVS@?d74~|XqjYkrNI%DuheE9jAI)yGkV-)%P#7v|jRV>4+ww}tGf<95 zZrX}GwefMt&2QEo*|Wa7`4&&M9wE@KhpgVu$dZL|a`F&b<09VEX?Q#(nd3ZzRy-P< zboK&u=$XOJ{i*8ioNP`}m%ib6q_H!TgTMSc+$4X0FN>FR3w8?4c7T(e^|K7DYfjPRQt!o!*lm{{wY(Q&HVkDilBQ}c$Qn&K*a zF1de3YvD0#&5{cEV$UAtA|wjt!O+@dXVCcYQN9~3*9Aw~3Bon3GPuFfn^za;U{Mg0 z*50S}y5k(j?r!e>hB?Fl`PNRAatHlSetI9;cJ-%kMm*4d%U4kJwWwd;$tj(pgTYim zGfV6RfaN%)RUDA(fL{2TGY;+yZ(k(R-1RZ0oE^Y?n0!_?zcm&nZrF8LvGIFg5=-83 z)nJ3Pdw^)BZ5x#`0bfcm`{uma5|Ck-y%DjI0GZ`CBuP(?EBc}9e&%uI?5ZWbj(^#z zSC$7A^AL4+;`k1+NXm(ERBq~!8)dxrBxf8597_n^sc^Nep^sb);EzjKZGfo8hKJF$ zHt&~uGS4Uu3+ZnJml3H6S7p1K>PTU>Y5zDTfMQi(D#Ws zt-*q3tAWv;Yr8MMkTj}$sJlo*&$UadwjIs`e*^F5P@A$yf8egU17VhbS39fs7#9o* z?1IyVMJloem8ls{nj1m(EG4Xoxy(JF?jKSQm%l}N5x-m>H6}l)QW+Q^*bF#b`3i%_ z#;pS)tpS5S*$^!s+5Ll;^QacUG|rikr)#WXdLL|8s`d=nmsbpQ;mw5heb_CFU84VH z>1-Urv!`QU!992yRVdcZQAg17 zKS3ODl=_-IWB01p3}IE6)7L%Dcc;fHcYdTt9Fx1j81xH8^d7d&4ra0W$i$>ZB; zZ_Rs(^1bZIAC;3sAK@yki+>q+aAyF=e(JQ*0$$IPox}Nj#CTZyPKAn%+gj^@0x>AW zS>~L{SrvZu7+KqTL@ZWiLuj`F}Nw2D@Ol*PsW!*Ogvub z&N)zR!4_a%7wn6OSq8(3xAN=&ex4X1Lw3zCrrp_aFe53>`q7K3sqd_?uuPnP@E9k| zkGu%a!QH$*KRQ8!g)4vW0e2wcX0XsE|_H=2Zy-qqi(!} zciimvDImZrIC)dWjCvKuq(DxRZM#*;j0C6Jqo9it9KIX;{6V!LEy|GzOv25=m)~Iv z-E$&$50w7klY9U0%w8Cf{fEeexXRVm%7^<2y^hvZm&})9#q4APmZwx`jzQ_`lR0XD zSB5`9%+VYBHFYp)xoHSLgf+JISdw;sw>w_HxqBldKF@AZ{ywgw5W`^dH(qWAja z?l+qlKLt^CsL)BsgUa~-!=de_e;pvp^$&BRcXO6O~gDgRvSpdlF6Kx6&4VZn-W>tURv zP#6Bb^5?KCIYW_qju{Yvz?K=VuqBafH_gw3Wof*ah*n1H-^~KBu3KoP`-p98~ zk4rjtpcKDEyJ>fDDic``nF6byQ5n3Y>rV};EI>}1GQ`TmuHIq8c(hXkzWKhD?=hY- zX7b#VzVwb8uGA^H5zd$@6$9&~6I#A?IBmh#kN$iKqrt9p&?g62pe0KXT&6AY1aFcj zzyEy4ikSQb9B;HZaS;VFAYEn%UtO9>a_p1Mrk!pVE1wz7W6&hh1WlOnuOlI)FD8!qH2^UFj0 zuAUdz8Vb;3@j`3u6f=~DKAdbZOAiSchNyjC?~X|!lF!by3^pRDMbG+eCa?c(5+6?l zI=WEd>}aJptV;HLG!bnk*nppD$7X)pa+mr;Ek>(r%-Z;p{j zFwp4_0Hdznt9()0Q|dEVi8o&0nZSJd=Pm6b8FMy|umuCRibIeW;fjNJkMmgl;>q{e zHyYzLK)z;8t{zT4y0_F9>R>&CMFSjSr>5?wY##3{q*c8GKMX3uND60!cMrPk17(Av zXFFF4yw}`kl4YXOI&%21hmNmrK(-xnBOPNFaIfM}Z;#zv38L7++d1m+xkC2lbPYl2 z&Ynp4hPvPv3>vU9;K^2%N<mV^q~6;m3+u~VH@QC>3&wV7V3yrZ3zr*U6s^Ke)54n$K0tbf8F zV1be$sTBh`npmAt5?JB0R(2N~nxauQg~&S$1zkUJ+V1CXIR7tob;Xz_qkJ@REy8jO z&ydcn1Q?ghJM5wms9XJK#)t(eE$143p&P{X3jL2HLozmCBdiOogM~Hf*~j}~UZpy{ zS+0fVrcpSPWynV$Q+R=C`=*)X9=l-k$N2p%7ucSa;1CD^JRxJ~p64!uFpfTgt}8)s2Leo9%zNTWOktPFo@fJ0J9p3gJA` z4?;mC>TOtrn@tmmrBWt^veD~r|NK*}k0|oC-B@T+F!qizCe-pg3GT?lDX@9Oo8{3+ zMlp>^LuzP6rKBZnW#W0H1Px9;H6NuFjup#vXIs!@FP3*!?dN882t!*ITF6_J=1Ds@!gW zZg!s5BF-Gvcu6`u_bkIp!xvf2IhW&$20#|&#Wleh5x`j~D&BoPeY^9~1-{6tIzDF; zOhTVyJMm^qQNhP3E9E!{Crjqs;GiM?h(d-N2h_U)(fj%ELXe3&PmnlQlSinED~roO z%Y*c8y7mXTqfMIhkwJ7F?Q&ZiKCYKcUfzpA;Po0axJ*~-GY?;h_$bGpiQH?uI95nY zCe$%Wj_3wUQUacyZxbr!U5n$0Ggu(!SJTK7xW+`fJP>~OIFA=T`b#(P)-tIc;bOQ} z1DV&0+q~hB+jmI#{ph=AJIaV8Y*Z9nm}nCeIT$H}yH1(Ay+Vfm!U8>n<-|-6Z4c~~ zD2y6xS&CRGQk3tM%M3l!C^kCZkj0p~_TeK?(zSAEajFVus5Uaz#mS2Qq15F(=tq@G z)+sUg{gPh=3eQ&+I4qXvtLmyLPIk}R+_b=V9A54$b989_fmtHV@%{hhkb(z`n4zZ!K?MJw6`qBim7ATH zlQSbk4?^gFE~fP$I#Z%x5tB~P!CAR^|8M1F^y@DoJ<}8*RW|k(F zmSz?v>^v;&rrd07oR+3s|2;%YZVp}{0ZS8eOBPmh78Y&`6ILD*3v&}w7A{^kZVq!^ zb9NpRb|J(6sXjAP5KtP7a1{6L zZ_=_G*}9((%#&Zb%%M7}y^<%&WEZxABSca&_rNg}3N1UX#6?D+{e3z_H}sVy75opH zufG4nMnd36G`wXs+1R$7Y;0#^=iTSvt2$NR&+eM(o~x&( zrh9s>i7SkZ4pbWo1rafNW(GDmik_#!PdHXq5+)LRBP%#wUJ^zbOFL6TCrd9=6B6cs z5(x_@J2Mj-38MswHVF$8*AEhw9~>mQB#iPTtehl_q9mMbT>q4eawN=5B#bKmhO@D8 zu#oWc!|5==~i<7CLEu2TT zv5|?vj=6!6fdMBh=~`WY#IP6B3l?22GHIK9kc8ZjfeV3~4>D;68o^S}%EH3* zolfcj!wA7e$wI=u{(C~L;aAr0-vI#uO=QJ`E@B#{(i&4!%cdLl%{jI_8|^kTh%3?c zsrBHi4FKD$a@E z&am7x`%ZL)ge6+(qoL&I`v}T^1tEPUBk+fyUV{!R%J;_>0sG&hH|)PZzUmnDeeUFj z@H3)B&Rm?^w#jKQBdFOk7Jp)n9XYkUsNc&!+yX{f!=8%L{G^tQm@D#!I?DT-*S ziG*#IY5(YyTA%)rrk6M14SGPf!L^}+RZfHHni^os;WLG@a`QEUB_>IP$lKLHQf)2Z z3=E)(Tiz#il%}+Iu38cLnw*@+5gVnrA^zxCJ5#|JwrM75wn3Zo=KUT99-9jN)?BO2 zdpper4K-Kc_cFc278grl(SOEar!Zv&m4`7q;Pq!$Z4+ z<%#8ME-=Vq8;^V-05yGDk$z`&5%vfb2e8m`^MOT{7fa(9FZrJdj95+*S}#@aZ@)}V{>ubQ-zWaEVj15B&s8z_bUeooCgzP)#s zXu6qnujtC3Sa4*ap4whS83#1e382wwSdg1*))73spc?n{t_r@Wa3bDpQUvqFYpgEo z7pm!;`p0YxCZ4eE+h^69#Ku(sD!2Bd?Y^zcQ9PZvXpc_1OT&1j4Ni$wgd<~&Avbmz zvixltrI)W|`ff>*OZ#uGHdeapKD_lSsE+{+??1HJd^b4ny1HtEJcaxCi@;+pmBlUL zMc7K>T)k}vp$wfI_m&RN>|Vo_FrEHi(`G5ExO8xqQDO$)b`UDfJ?h$E+Q;uroUvO4 zi=&vJv0aP_Rdt#RChbaWmPX&c84UWIOpJ`DN6@7#yoPCvJl`cBz%gQbYRPy!#hv1y zR$0EtJK)yiM>tl8cOxnUl>;Ge=YNU8vX6fXd)&c%!N!BY!S@S?e}jbhcx@Stj7ZE6 z4^~+t4bXtJuQT}^ykrZmaG?;z<@}B=T1mWLJthIEq_Y6q6^uqHpXU?7yI_u;=CS2M z=|!&)C6g;!;a1((pgdbni}cQm+um?`?o{vR*j(pNXG&`FH@cbPs|sjN2}p{TV7W{7 z!f=?U3#l5(7DP&g*4w{`m#GAqekFi`_T<&CfFmqESnnlIua7Ww@f>_kY^_(3>NNU7TtN@5O3>=sO1k$ShoO)iZ)J!Qc$J^b(>pY%d4$W0+DWhsVG)!0-3~B6T(a- zz$Ewx<|j7%lRkm>0^OLcqv{TZ%t zw(nm><|A>+IKN#mkm5Fp++40>^T+-f&1YuH?ChairBh(Dk~%om-0s1R+;#c)>Hez! z>0}B8NZWWoUj)1`2oEGd3Llm|XTwuVQx$>f3#a=V?8*bW-8B+o@&kqoU#k9_2-og} zzsJlXV?4zHsU{H!8au2VMhw*Wwn0Bs$TQl}PgrfrXfGNP;X$>mviT;B+C;1avhG2%F2m$+EAe0Pnz`b9>o zPd^32BZ$MuIy{NOTV-RAcrX~GRHN5#zL_rki8SCoWK`iG;R znx`9>DNHQ`jEkE2@rtGOOQ|X*(8-kgkkVuF!r+zSOlWcPa zb^WM1oi*Q>vbZxbELB%f`SVW11#i=7u-iRGkZLDy%s{SKxvab)Jwv%pfA!zpQ8CFK>KjXDmb{gL>sAyRPrx>4NKZtg?ys!or z{Jz}xg@MNP6Poi_0x4iNP=4J}h#6pmQ#Km9H86Lty`{$`={x{$ZB0qUImub0qoZ>e!>{V@zIx#!#R{owh|D&~>f< z#O|;cT7_4*CSu*q9L;=iO9h`R-*h$5nKJWt$zWn9F<=7TR+z!{!Dh(vHUKb$uTvUNmp|P1p8a|p^f)}ubdY1D--wB{55w-Vp^Tao#*?)4bfQri;a=4 zjfUbEnSr-Wlfw;Tbt;x~aRu<(?+a*bZx-aDojfJVf}jXI`Fou~>lMW!(m%%uAUrM~ zH0C-r|7bjLO}+*_o2L&NJ9W>r1U7V)IcVbiY~FV7*yY$$l%01&#gmhYJtH$iba?25 z9Sv97UML*-4;eW_-|LJ&25_}*v#z(^d+o3+>FrWc%FB}Pj!}wj5;$3D7HK4*IGI{L zH98YCzhQX1*ebyoA6@HMXSbv=`a$!4I~w>;rSm`a#Q)ShY)t>j*S|O7U?Px#u`&O* zAkPU#4#vjvUjjNaC)fX%!L$6!>N$S=NZZ|kzyw&hnE!9a8`A=*kadp55Z!?pMk*B5 zf#Gi97`6ur20_*OPxCXO*~4*VPwfw3WJkxj>BQRR@%z_gS5gM~jMhxUllO8KEMiCl zUSoPi4ztAi^m0T-PDl(fNdZai)HJAp@xF4`!v*Hi@O z#2}6?kD(sMeUkT~#E(t1bu@l{IMmo&>e%vq1x@xgmzn|5hG#Z2m4@(c4p3cb?^$<7 zKVNKrKy!h%0&Ahul0}HUWW~ z6AY`sC!;F-{mNP7hGy1h-E|lGjVbn^%~Z`7msouf>nfs2C4w8vuV-lnV2$llgVnm8 zUSe$;^?hUs%)rdt_>Fjb!YxCiONTg?G4p)^(n~YpAq)80RW5aKY7YJ33P0P}0$9(xb6Ug}-U z9<(~~i)0JC^xgh`Px&3X%M?i1wjTsFQ2mJE1g*CEBI!

)k$~i27?k2yMXj0{!8L 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

lwv1b0UTjc(uCKy^h$0v$LE1_xd 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 );B=5&?nQnz=9u22_cs%6xiB< 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 GHw6`zFxl|{ diff --git a/examples/userPropagator/user_propagator.h b/examples/userPropagator/user_propagator.h new file mode 100644 index 000000000..6c12ee2f3 --- /dev/null +++ b/examples/userPropagator/user_propagator.h @@ -0,0 +1,87 @@ +#pragma once + +#include "common.h" + +class user_propagator : public z3::user_propagator_base { + +protected: + + unsigned board; + std::unordered_map &queenToY; + simple_model currentModel; + std::unordered_set modelSet; + z3::expr_vector fixedValues; + std::stack fixedCnt; + + int solutionNr = 1; + +public: + + int getModelCount() const { + return solutionNr - 1; + } + + void final() override { + this->conflict(fixedValues); + if (modelSet.find(currentModel) != modelSet.end()) { + WriteLine("Got already computed model"); + return; + } + Write("Model #" << solutionNr << ":\n"); + solutionNr++; +#ifdef VERBOSE + for (unsigned i = 0; i < fixedValues.size(); i++) { + z3::expr fixed = fixedValues[i]; + WriteLine("q" + to_string(queenToY[fixed]) + " = " + to_string(currentModel[queenToY[fixed]])); + } +#endif + modelSet.insert(currentModel); + WriteEmptyLine; + } + + static unsigned bvToInt(z3::expr const &e) { + return (unsigned) e.get_numeral_int(); + } + + void fixed(z3::expr const &ast, z3::expr const &value) override { + fixedValues.push_back(ast); + unsigned valueBv = bvToInt(value); + currentModel[queenToY[ast]] = valueBv; + } + + user_propagator(z3::context &c, std::unordered_map &queenToY, unsigned board) + : user_propagator_base(c), board(board), queenToY(queenToY), fixedValues(c), currentModel(board, (unsigned) -1) { + + this->register_fixed(); + this->register_final(); + } + + user_propagator(z3::solver *s, std::unordered_map &idMapping, unsigned board) + : user_propagator_base(s), board(board), queenToY(idMapping), fixedValues(s->ctx()), currentModel(board, (unsigned) -1) { + + this->register_fixed(); + this->register_final(); + } + + ~user_propagator() = default; + + void push() override { + fixedCnt.push((unsigned) fixedValues.size()); + } + + void pop(unsigned num_scopes) override { + for (unsigned i = 0; i < num_scopes; i++) { + unsigned lastCnt = fixedCnt.top(); + fixedCnt.pop(); + // Remove fixed values from model + for (unsigned j = fixedValues.size(); j > lastCnt; j--) { + currentModel[queenToY[fixedValues[j - 1]]] = (unsigned) -1; + } + fixedValues.resize(lastCnt); + } + } + + user_propagator_base *fresh(z3::context &) override { + return this; + } +}; \ No newline at end of file diff --git a/examples/userPropagator/user_propagator_created_maximisation.h b/examples/userPropagator/user_propagator_created_maximisation.h new file mode 100644 index 000000000..7ef93b8fe --- /dev/null +++ b/examples/userPropagator/user_propagator_created_maximisation.h @@ -0,0 +1,338 @@ +#pragma once + +#include "common.h" + +class user_propagator_created_maximisation : public z3::user_propagator_base { + + + std::unordered_map argToFcts; + std::unordered_map fctToArgs; + + std::unordered_map currentModel; + z3::expr_vector fixedValues; + std::vector fixedCnt; + + user_propagator_created_maximisation* childPropagator = nullptr; + user_propagator_created_maximisation* parentPropagator = nullptr; + + int board; + int nesting; // Just for logging (0 ... main solver; 1 ... sub-solver) + +public: + + user_propagator_created_maximisation(z3::context &c, user_propagator_created_maximisation* parentPropagator, unsigned board, int nesting) : + z3::user_propagator_base(c), fixedValues(c), parentPropagator(parentPropagator), board(board), nesting(nesting) { + + this->register_fixed(); + this->register_final(); + this->register_created(); + } + + user_propagator_created_maximisation(z3::solver *s, unsigned board) : + z3::user_propagator_base(s), fixedValues(s->ctx()), board(board), nesting(0) { + + this->register_fixed(); + this->register_final(); + this->register_created(); + } + + ~user_propagator_created_maximisation() { + delete childPropagator; + } + + void final() override { + WriteLine("Final (" + to_string(nesting) + ")"); + } + + void push() override { + WriteLine("Push (" + to_string(nesting) + ")"); + fixedCnt.push_back((unsigned) fixedValues.size()); + } + + void pop(unsigned num_scopes) override { + WriteLine("Pop (" + to_string(nesting) + ")"); + for (unsigned i = 0; i < num_scopes; i++) { + unsigned lastCnt = fixedCnt.back(); + fixedCnt.pop_back(); + for (auto j = fixedValues.size(); j > lastCnt; j--) { + currentModel.erase(fixedValues[j - 1]); + } + fixedValues.resize(lastCnt); + } + } + + void checkValidPlacement(std::vector &conflicts, const z3::expr &fct, const z3::expr_vector &args, const std::vector &argValues, int pos) { + unsigned queenId = pos; + unsigned queenPos = argValues[pos]; + z3::expr queenPosExpr = args[pos]; + + if (queenPos >= board) { + z3::expr_vector conflicting(ctx()); + conflicting.push_back(fct); + conflicting.push_back(queenPosExpr); + conflicts.push_back(conflicting); + return; + } + + for (unsigned otherId = 0; otherId < argValues.size(); otherId++) { + if (otherId == pos) + continue; + + unsigned otherPos = argValues[otherId]; + z3::expr otherPosExpr = args[otherId]; + + if (otherPos == (unsigned)-1) + continue; // We apparently do not have this value + + if (queenPos == otherPos) { + z3::expr_vector conflicting(ctx()); + conflicting.push_back(fct); + conflicting.push_back(queenPosExpr); + conflicting.push_back(otherPosExpr); + conflicts.push_back(conflicting); + } + int diffY = abs((int) queenId - (int) otherId); + int diffX = abs((int) queenPos - (int) otherPos); + if (diffX == diffY) { + z3::expr_vector conflicting(ctx()); + conflicting.push_back(fct); + conflicting.push_back(queenPosExpr); + conflicting.push_back(otherPosExpr); + conflicts.push_back(conflicting); + } + } + } + + unsigned getValues(const z3::expr &fct, std::vector &argValues) const { + z3::expr_vector args = fctToArgs.at(fct); + unsigned fixed = 0; + for (const z3::expr &arg: args) { + if (currentModel.contains(arg)) { + argValues.push_back(currentModel.at(arg)); + fixed++; + } + else + argValues.push_back((unsigned) -1); // no value so far + } + return fixed; + } + + + user_propagator_base *fresh(z3::context &ctx) override { + WriteLine("Fresh context"); + childPropagator = new user_propagator_created_maximisation(ctx, this, board, nesting + 1); + return childPropagator; + } + + void fixed(const z3::expr &expr, const z3::expr &value) override { + // Could be optimized! + WriteLine("Fixed (" + to_string(nesting) + ") " + expr.to_string() + " to " + value.to_string()); + unsigned v = value.is_true() ? 1 : (value.is_false() ? 0 : value.get_numeral_uint()); + currentModel[expr] = v; + fixedValues.push_back(expr); + + z3::expr_vector effectedFcts(ctx()); + bool fixedFct = fctToArgs.contains(expr); + + if (fixedFct) { + // fixed the value of a function + effectedFcts.push_back(expr); + } + else { + // fixed the value of a function's argument + effectedFcts = argToFcts.at(expr); + } + + for (const z3::expr& fct : effectedFcts) { + if (!currentModel.contains(fct)) + // we do not know yet whether to expect a valid or invalid placement + continue; + + std::vector values; + unsigned fixedArgsCnt = getValues(fct, values); + bool fctValue = currentModel[fct]; + z3::expr_vector args = fctToArgs.at(fct); + + if (!fctValue) { + // expect invalid placement ... + if (fixedArgsCnt != board) + // we expect an invalid placement, but not all queen positions have been placed yet + return; + std::vector conflicts; + for (unsigned i = 0; i < args.size(); i++) { + if (values[i] != (unsigned)-1) + checkValidPlacement(conflicts, expr, args, values, i); + } + + if (conflicts.empty()) { + // ... but we got a valid one + z3::expr_vector conflicting(ctx()); + conflicting.push_back(fct); + for (const z3::expr &arg: args) { + if (!arg.is_numeral()) + conflicting.push_back(arg); + } + this->conflict(conflicting); + } + else { + // ... and everything is fine; we have at least one conflict + } + } + else { + // expect valid placement ... + std::vector conflicts; + if (fixedFct){ + for (unsigned i = 0; i < args.size(); i++) { + if (values[i] != (unsigned)-1) // check all set queens + checkValidPlacement(conflicts, expr, args, values, i); + } + } + else { + for (unsigned i = 0; i < args.size(); i++) { + if (z3::eq(args[i], expr)) // only check newly fixed values + checkValidPlacement(conflicts, fct, args, values, i); + } + } + if (conflicts.size() > 0) { + // ... but we got an invalid one + for (const z3::expr_vector &conflicting: conflicts) + this->conflict(conflicting); + } + else { + // ... and everything is fine; no conflict + } + } + } + } + +// void fixed(const z3::expr &expr, const z3::expr &value) override { +// WriteLine("Fixed (" + to_string(nesting) + ") " + expr.to_string() + " to " + value.to_string()); +// unsigned v = value.is_true() ? 1 : (value.is_false() ? 0 : value.get_numeral_uint()); +// currentModel[expr] = v; +// fixedValues.push_back(expr); +// +// if (fctToArgs.contains(expr)) { +// // fixed the value of a function +// +// std::vector values; +// unsigned fixedArgsCnt = getValues(expr, values); +// +// if (!v && fixedArgsCnt != board) +// // we expect an invalid placement, but not all queen positions have been placed yet +// return; +// +// z3::expr_vector args = fctToArgs.at(expr); +// +// std::vector conflicts; +// for (unsigned i = 0; i < args.size(); i++) { +// if (values[i] != (unsigned)-1) +// checkValidPlacement(conflicts, expr, args, values, i); +// } +// if (v) { +// //we expected a valid queen placement +// if (conflicts.size() > 0) { +// // ... but we got an invalid one +// for (const z3::expr_vector &conflicting: conflicts) +// this->conflict(conflicting); +// } +// else { +// // everything fine; no conflict +// } +// } +// else { +// // we expect an invalid queen placement +// if (conflicts.empty()) { +// // ... but we got a valid one +// z3::expr_vector conflicting(ctx()); +// conflicting.push_back(expr); +// for (const z3::expr &arg: args) { +// if (!arg.is_numeral()) +// conflicting.push_back(arg); +// } +// this->conflict(conflicting); +// } +// else { +// // everything fine; we have at least one conflict +// } +// } +// } +// else { +// // fixed the value of a function argument +// +// z3::expr_vector effectedFcts = argToFcts.at(expr); +// +// for (const z3::expr& fct : effectedFcts) { +// if (!currentModel.contains(fct)) +// // we do not know yet whether to expect a valid or invalid placement +// continue; +// +// std::vector values; +// unsigned fixedArgsCnt = getValues(fct, values); +// bool fctValue = currentModel[fct]; +// z3::expr_vector args = fctToArgs.at(fct); +// +// if (!fctValue) { +// // expect invalid placement +// if (fixedArgsCnt != board) +// // we expect an invalid placement, but not all queen positions have been placed yet +// return; +// std::vector conflicts; +// for (unsigned i = 0; i < args.size(); i++) { +// if (values[i] != (unsigned)-1) +// checkValidPlacement(conflicts, expr, args, values, i); +// } +// +// if (conflicts.empty()) { +// // ... but we got a valid one +// z3::expr_vector conflicting(ctx()); +// conflicting.push_back(fct); +// for (const z3::expr &arg: args) { +// if (!arg.is_numeral()) +// conflicting.push_back(arg); +// } +// this->conflict(conflicting); +// } +// else { +// // everything fine; we have at least one conflict +// } +// } +// else { +// // expect valid placement +// std::vector conflicts; +// for (unsigned i = 0; i < args.size(); i++) { +// if (z3::eq(args[i], expr)) // only check newly fixed values +// checkValidPlacement(conflicts, fct, args, values, i); +// } +// if (conflicts.size() > 0) { +// // ... but we got an invalid one +// for (const z3::expr_vector &conflicting: conflicts) +// this->conflict(conflicting); +// } +// else { +// // everything fine; no conflict +// } +// } +// } +// } +// } + + void created(const z3::expr &func) override { + WriteLine("Created (" + to_string(nesting) + "): " + func.to_string()); + z3::expr_vector args = func.args(); + for (unsigned i = 0; i < args.size(); i++) { + z3::expr arg = args[i]; + + if (!arg.is_numeral()) { + WriteLine("Registered " + arg.to_string()); + this->add(arg); + } + else { + currentModel[arg] = arg.get_numeral_uint(); + // Skip registering as argument is a fixed BV; + } + + argToFcts.try_emplace(arg, ctx()).first->second.push_back(func); + } + fctToArgs.emplace(std::make_pair(func, args)); + } +}; \ No newline at end of file diff --git a/examples/userPropagator/user_propagator_internal_maximisation.h b/examples/userPropagator/user_propagator_internal_maximisation.h new file mode 100644 index 000000000..7a22270eb --- /dev/null +++ b/examples/userPropagator/user_propagator_internal_maximisation.h @@ -0,0 +1,30 @@ +#pragma once + +#include "user_propagator_with_theory.h" + +class user_propagator_internal_maximisation : public user_propagator_with_theory { + + z3::expr manhattanSum; + +public: + + int best = -1; + + user_propagator_internal_maximisation(z3::solver *s, std::unordered_map &idMapping, unsigned board, z3::expr_vector queens) + : user_propagator_with_theory(s, idMapping, board), + manhattanSum(s->ctx().bv_val(0, queens[0].get_sort().bv_size())) { + for (int i = 1; i < queens.size(); i++) { + manhattanSum = manhattanSum + z3::ite(z3::uge(queens[i], queens[i - 1]), queens[i] - queens[i - 1], queens[i - 1] - queens[i]); + } + } + + void final() override { + + int current = 0; + for (unsigned i = 1; i < board; i++) { + current += abs((signed) currentModel[i] - (signed) currentModel[i - 1]); + } + best = std::max(current, best); + this->propagate(z3::expr_vector(ctx()), z3::ugt(manhattanSum, best)); + } +}; \ No newline at end of file diff --git a/examples/userPropagator/user_propagator_subquery_maximisation.h b/examples/userPropagator/user_propagator_subquery_maximisation.h new file mode 100644 index 000000000..47382c435 --- /dev/null +++ b/examples/userPropagator/user_propagator_subquery_maximisation.h @@ -0,0 +1,51 @@ +#pragma once + +#include "user_propagator.h" + +class user_propagator_subquery_maximisation : public user_propagator { + + z3::expr assertion; + z3::expr_vector queens; + z3::expr manhattanSum; + +public: + + user_propagator_subquery_maximisation(z3::solver *s, std::unordered_map &idMapping, unsigned board, z3::expr_vector queens) + : user_propagator(s, idMapping, board), + assertion(mk_and(s->assertions())), + queens(queens), manhattanSum(s->ctx().bv_val(0, queens[0].get_sort().bv_size())) { + + for (int i = 1; i < queens.size(); i++) { + manhattanSum = manhattanSum + z3::ite(z3::uge(queens[i], queens[i - 1]), queens[i] - queens[i - 1], queens[i - 1] - queens[i]); + } + } + + void final() override { + + int max1 = 0; + for (unsigned i = 1; i < board; i++) { + max1 += abs((signed) currentModel[i] - (signed) currentModel[i - 1]); + } + z3::expr_vector vec(ctx()); + + int max2 = 0; + z3::solver subquery(ctx(), z3::solver::simple()); + + subquery.add(assertion); + subquery.add(z3::ugt(manhattanSum, max1)); + if (subquery.check() == z3::unsat) + return; // model is already maximal + + z3::model counterExample = subquery.get_model(); + + int prev, curr = -1; + + for (int i = 0; i < queens.size(); i++) { + prev = curr; + curr = counterExample.eval(queens[i]).get_numeral_int(); + if (i == 0) continue; + max2 += abs(curr - prev); + } + this->propagate(vec, z3::uge(manhattanSum, max2)); + } +}; \ No newline at end of file diff --git a/examples/userPropagator/user_propagator_with_theory.h b/examples/userPropagator/user_propagator_with_theory.h new file mode 100644 index 000000000..cd3e6f273 --- /dev/null +++ b/examples/userPropagator/user_propagator_with_theory.h @@ -0,0 +1,50 @@ +#pragma once + +#include "user_propagator.h" + +class user_propagator_with_theory : public user_propagator { + +public: + + user_propagator_with_theory(z3::context &c, std::unordered_map &idMapping, unsigned board) + : user_propagator(c, idMapping, board) {} + + user_propagator_with_theory(z3::solver *s, std::unordered_map &idMapping, unsigned board) + : user_propagator(s, idMapping, board) {} + + void fixed(z3::expr const &ast, z3::expr const &value) override { + unsigned queenId = queenToY[ast]; + unsigned queenPos = bvToInt(value); + + if (queenPos >= board) { + z3::expr_vector conflicting(ast.ctx()); + conflicting.push_back(ast); + this->conflict(conflicting); + return; + } + + for (const z3::expr &fixed: fixedValues) { + unsigned otherId = queenToY[fixed]; + unsigned otherPos = currentModel[queenToY[fixed]]; + + if (queenPos == otherPos) { + z3::expr_vector conflicting(ast.ctx()); + conflicting.push_back(ast); + conflicting.push_back(fixed); + this->conflict(conflicting); + continue; + } + int diffY = abs((int) queenId - (int) otherId); + int diffX = abs((int) queenPos - (int) otherPos); + if (diffX == diffY) { + z3::expr_vector conflicting(ast.ctx()); + conflicting.push_back(ast); + conflicting.push_back(fixed); + this->conflict(conflicting); + } + } + + fixedValues.push_back(ast); + currentModel[queenToY[ast]] = queenPos; + } +}; \ No newline at end of file From 8d1276fa60863c1d4cb726f5c0a6362bac12fdcc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 11:03:31 -0800 Subject: [PATCH 093/258] using directives Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 26 ++++++++++++++++++++++++++ src/api/dotnet/NativeModel.cs | 7 ++++++- src/api/dotnet/NativeSolver.cs | 5 +++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 42a9bab90..a9c4ab775 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -1,3 +1,29 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + NativeContext.cs + +Abstract: + + Z3 Managed API: Native Context + +Author: + + Christoph Wintersteiger (cwinter) 2012-03-22 + Nikolaj Bjorner (nbjorner) 2022-03-01 + +Notes: + +--*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; + namespace Microsoft.Z3 { using Z3_app = System.IntPtr; diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index dc2be0cc8..a4a7f11be 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -19,6 +19,11 @@ Notes: --*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Diagnostics; + namespace Microsoft.Z3 { using Z3_ast = System.IntPtr; @@ -36,7 +41,7 @@ namespace Microsoft.Z3 ///

/// A Constant /// An expression if the constant has an interpretation in the model, null otherwise. - public Z3_ast ConstInterp(Z3_ast a) => ConstInterp(Native.Z3_get_app_decl(Context.nCtx, a)); + public Z3_ast ConstInterp(Z3_ast a) => ConstFuncInterp(Native.Z3_get_app_decl(Context.nCtx, a)); /// /// Retrieves the interpretation (the assignment) of in the model. diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs index 20d6a8e6f..00110d550 100644 --- a/src/api/dotnet/NativeSolver.cs +++ b/src/api/dotnet/NativeSolver.cs @@ -18,6 +18,11 @@ Notes: --*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Diagnostics; + namespace Microsoft.Z3 { From cd324a4734bef41e0520d53a3a917aca761754a0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 11:07:00 -0800 Subject: [PATCH 094/258] na Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index a9c4ab775..604d752b2 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -12,10 +12,8 @@ Abstract: Author: Christoph Wintersteiger (cwinter) 2012-03-22 - Nikolaj Bjorner (nbjorner) 2022-03-01 - -Notes: - + John Fleisher, Nikolaj Bjorner (nbjorner) 2022-03-01 + --*/ using System; From e1e8d15827ecb727e38776d57b20ce7e7afd37ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 11:38:23 -0800 Subject: [PATCH 095/258] stub out array serialization Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 16 +++------- src/api/dotnet/NativeModel.cs | 55 ++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 604d752b2..6961b39dd 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -232,11 +232,10 @@ namespace Microsoft.Z3 /// /// A string representing the Term value in decimal notation. /// A Term with value and sort Real - public Z3_ast MkReal(string v, Z3_sort realSort) + public Z3_ast MkReal(string v) { Debug.Assert(!string.IsNullOrEmpty(v)); - - return Native.Z3_mk_numeral(nCtx, v, realSort); + return Native.Z3_mk_numeral(nCtx, v, MkRealSort()); } /// @@ -378,11 +377,7 @@ namespace Microsoft.Z3 /// /// Creates a Boolean value. /// - public Z3_ast MkBool(bool value) - { - - return value ? MkTrue() : MkFalse(); - } + public Z3_ast MkBool(bool value) => value ? MkTrue() : MkFalse(); /// /// Create an expression representing t1 iff t2. @@ -1166,7 +1161,7 @@ namespace Microsoft.Z3 Debug.Assert(v != IntPtr.Zero); int result = i = 0; - if (Native.Z3_get_numeral_int(nCtx, v, ref result) == 0) ; + if (Native.Z3_get_numeral_int(nCtx, v, ref result) == 0) { return false; } @@ -1197,8 +1192,7 @@ namespace Microsoft.Z3 /// Try to get long from AST /// /// - /// - /// + /// /// public bool TryGetNumeralInt64(Z3_ast v, out long i) { diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index a4a7f11be..6a8ff21cf 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -263,35 +263,46 @@ namespace Microsoft.Z3 /// Convert the interpretation of t into a sequence of array updates /// /// + /// /// null if the argument does evaluate to a sequence of stores to an array public bool TryGetArrayValue(Z3_ast t, out ArrayValue result) { var r = Eval(t, true); // check that r is a sequence of store over a constant default array. var updates = new List>(); - - //while (true) - //{ - // // check that r is an app, and the decl-kind is Z3_OP_ARRAY_CONST or Z3_OP_ARRAY_STORE - // // if it is Z3_OP_ARRAY_CONST then set result.Else and break; - // // if it is ARRAY_STORE, then append to 'updates' and continue - // // in other cases return null - // return false; - - //} - - if (updates.Any()) - { - result = new ArrayValue() - { - Updates = updates.ToArray() - }; - - return true; - } - result = null; - return false; + while (true) + { + if (Context.GetAstKind(r) != Z3_ast_kind.Z3_APP_AST) + return false; + Z3_func_decl f = Context.GetAppDecl(r); + var kind = Context.GetDeclKind(f); + if (kind == Z3_decl_kind.Z3_OP_CONST_ARRAY) + { +#if false +// TODO + result = new ArrayValue(); + result.Else = r; + result.Updates = updates.ToArray(); + result.Domain = updates.Select((x, y) => x).ToArray(); + result.Range = updates.Select((x, y) => y).ToArray(); +#endif + return true; + } + else if (kind == Z3_decl_kind.Z3_OP_STORE) + { +#if false + Debug.Assert(Context.NumArgs(r) == 3); + updates.Add(new KeyValuePair(Context.GetArg(r, 1), Context.GetArg(r, 2))); + r = Context.GetArg(r, 0); +#endif + } + else + { + return false; + } + } + return true; } /// From 248a3676affd9fefe886f1888decd49d508dd309 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 11:40:29 -0800 Subject: [PATCH 096/258] na Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index 6a8ff21cf..ffd4e0faf 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -254,9 +254,9 @@ namespace Microsoft.Z3 /// public Z3_ast Else; - public Z3_sort[] Domain; + public Z3_ast[] Domain; - public Z3_sort[] Range; + public Z3_ast[] Range; } /// From 35d26bc28210f3177f47293d7f93c22d5a595d21 Mon Sep 17 00:00:00 2001 From: John Fleisher Date: Thu, 3 Mar 2022 16:06:30 -0500 Subject: [PATCH 097/258] NativeModel: TryGetArrayValue (#5881) * WiP: Disposable, MkAdd, MkApp, MkBool, MkBoolSort, MkBound, MkBvSort, MkFalse, MkTrue, MkIntSort * WiP: Native z3 mk_ functions * WiP: mk_ functions for NativeContext * WiP: add utility functions for getting values * WiP: Adding more native utility functions * native model pull * WiP: NativeContext additions for array access * WiP: use Z3_symbol in place of managed Symbol * WiP: add solver, model, and array methods * WiP: MkSimpleSolver, MkReal * WiP: GetDomain GetRange * WiP: MkExists * Override for MkFuncDecl * MkConstArray, MkSelect * WiP: code cleanup * migrate Context reference to NativeContext * remove local signing from PR * minor code cleanup * Sorts to properties, fix usings, * make IntSort property * sort using * IntSort, RealSort - properties * WiP: get array value update Co-authored-by: jfleisher --- src/api/dotnet/NativeContext.cs | 27 +++++++---- src/api/dotnet/NativeModel.cs | 81 +++++++++++++++------------------ src/api/dotnet/NativeSolver.cs | 2 +- 3 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 6961b39dd..96e0487de 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -235,7 +235,7 @@ namespace Microsoft.Z3 public Z3_ast MkReal(string v) { Debug.Assert(!string.IsNullOrEmpty(v)); - return Native.Z3_mk_numeral(nCtx, v, MkRealSort()); + return Native.Z3_mk_numeral(nCtx, v, RealSort); } /// @@ -304,10 +304,14 @@ namespace Microsoft.Z3 #region Sort - public Z3_sort MkIntSort() => Native.Z3_mk_int_sort(nCtx); - public Z3_sort MkBoolSort() => Native.Z3_mk_bool_sort(nCtx); + /// + /// Sorts return same ptr for subsequent calls + /// + public Z3_sort IntSort => Native.Z3_mk_int_sort(nCtx); + public Z3_sort BoolSort => Native.Z3_mk_bool_sort(nCtx); + public Z3_sort RealSort => Native.Z3_mk_real_sort(nCtx); + public Z3_sort MkBvSort(uint size) => Native.Z3_mk_bv_sort(nCtx, size); - public Z3_sort MkRealSort() => Native.Z3_mk_real_sort(nCtx); public Z3_sort MkListSort(string name, Z3_sort elemSort, out Z3_func_decl inil, out Z3_func_decl iisnil, @@ -1086,17 +1090,24 @@ namespace Microsoft.Z3 /// public Z3_ast[] GetAppArgs(Z3_app app) { - Debug.Assert(app != IntPtr.Zero); - - var numArgs = Native.Z3_get_app_num_args(nCtx, app); + var numArgs = GetNumArgs(app); var args = new Z3_ast[numArgs]; for (uint i = 0; i < numArgs; i++) { - args[i] = Native.Z3_get_app_arg(nCtx, app, i); + args[i] = GetAppArg(app, i); } return args; } + public uint GetNumArgs(Z3_app app) + { + Debug.Assert(app != IntPtr.Zero); + + return Native.Z3_get_app_num_args(nCtx, app); + } + + internal Z3_ast GetAppArg(Z3_app app, uint i) => Native.Z3_get_app_arg(nCtx, app, i); + /// /// Get App Decl from IntPtr /// diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index ffd4e0faf..96eb13cd2 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -41,7 +41,7 @@ namespace Microsoft.Z3 /// /// A Constant /// An expression if the constant has an interpretation in the model, null otherwise. - public Z3_ast ConstInterp(Z3_ast a) => ConstFuncInterp(Native.Z3_get_app_decl(Context.nCtx, a)); + public Z3_ast ConstInterp(Z3_ast a) => ConstFuncInterp(Native.Z3_get_app_decl(ntvContext.nCtx, a)); /// /// Retrieves the interpretation (the assignment) of in the model. @@ -50,10 +50,10 @@ namespace Microsoft.Z3 /// An expression if the function has an interpretation in the model, null otherwise. public Z3_ast ConstFuncInterp(Z3_func_decl f) { - if (Native.Z3_get_arity(Context.nCtx, f) != 0) + if (Native.Z3_get_arity(ntvContext.nCtx, f) != 0) throw new Z3Exception("Non-zero arity functions have FunctionInterpretations as a model. Use FuncInterp."); - return Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); + return Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f); } /// @@ -63,11 +63,11 @@ namespace Microsoft.Z3 /// A FunctionInterpretation if the function has an interpretation in the model, null otherwise. public NativeFuncInterp FuncInterp(Z3_func_decl f) { - Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_range(Context.nCtx, f)); + Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(ntvContext.nCtx, Native.Z3_get_range(ntvContext.nCtx, f)); - if (Native.Z3_get_arity(Context.nCtx, f) == 0) + if (Native.Z3_get_arity(ntvContext.nCtx, f) == 0) { - IntPtr n = Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); + IntPtr n = Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f); if (sk == Z3_sort_kind.Z3_ARRAY_SORT) { @@ -75,10 +75,10 @@ namespace Microsoft.Z3 return null; else { - if (Native.Z3_is_as_array(Context.nCtx, n) == 0) + if (Native.Z3_is_as_array(ntvContext.nCtx, n) == 0) throw new Z3Exception("Argument was not an array constant"); - var fd = Native.Z3_get_as_array_func_decl(Context.nCtx, n); - return new NativeFuncInterp(Context, this, f, fd); + var fd = Native.Z3_get_as_array_func_decl(ntvContext.nCtx, n); + return new NativeFuncInterp(ntvContext, this, f, fd); } } else @@ -88,11 +88,11 @@ namespace Microsoft.Z3 } else { - IntPtr n = Native.Z3_model_get_func_interp(Context.nCtx, NativeObject, f); + IntPtr n = Native.Z3_model_get_func_interp(ntvContext.nCtx, NativeObject, f); if (n == IntPtr.Zero) return null; else - return new NativeFuncInterp(Context, this, f, n); + return new NativeFuncInterp(ntvContext, this, f, n); } } @@ -103,7 +103,7 @@ namespace Microsoft.Z3 /// public uint NumConsts { - get { return Native.Z3_model_get_num_consts(Context.nCtx, NativeObject); } + get { return Native.Z3_model_get_num_consts(ntvContext.nCtx, NativeObject); } } @@ -118,7 +118,7 @@ namespace Microsoft.Z3 uint n = NumConsts; Z3_func_decl[] res = new Z3_func_decl[n]; for (uint i = 0; i < n; i++) - res[i] = Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i); + res[i] = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i); return res; } } @@ -134,24 +134,22 @@ namespace Microsoft.Z3 uint nc = NumConsts; for (uint i = 0; i < nc; ++i) { - var f = Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i); - IntPtr n = Native.Z3_model_get_const_interp(Context.nCtx, NativeObject, f); + var f = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i); + IntPtr n = Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f); if (n == IntPtr.Zero) continue; yield return new KeyValuePair(f, n); } } } - /// /// The number of function interpretations in the model. /// public uint NumFuncs { - get { return Native.Z3_model_get_num_funcs(Context.nCtx, NativeObject); } + get { return Native.Z3_model_get_num_funcs(ntvContext.nCtx, NativeObject); } } - /// /// The function declarations of the function interpretations in the model. /// @@ -163,12 +161,11 @@ namespace Microsoft.Z3 uint n = NumFuncs; Z3_func_decl[] res = new Z3_func_decl[n]; for (uint i = 0; i < n; i++) - res[i] = Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i); + res[i] = Native.Z3_model_get_func_decl(ntvContext.nCtx, NativeObject, i); return res; } } - /// /// All symbols that have an interpretation in the model. /// @@ -182,9 +179,9 @@ namespace Microsoft.Z3 uint n = nFuncs + nConsts; Z3_func_decl[] res = new Z3_func_decl[n]; for (uint i = 0; i < nConsts; i++) - res[i] = Native.Z3_model_get_const_decl(Context.nCtx, NativeObject, i); + res[i] = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i); for (uint i = 0; i < nFuncs; i++) - res[nConsts + i] = Native.Z3_model_get_func_decl(Context.nCtx, NativeObject, i); + res[nConsts + i] = Native.Z3_model_get_func_decl(ntvContext.nCtx, NativeObject, i); return res; } } @@ -200,7 +197,6 @@ namespace Microsoft.Z3 public ModelEvaluationFailedException() : base() { } } - /// /// Evaluates the expression in the current model. /// @@ -219,7 +215,7 @@ namespace Microsoft.Z3 { IntPtr v = IntPtr.Zero; - if (Native.Z3_model_eval(Context.nCtx, NativeObject, t, (byte)(completion ? 1 : 0), ref v) == (byte)0) + if (Native.Z3_model_eval(ntvContext.nCtx, NativeObject, t, (byte)(completion ? 1 : 0), ref v) == (byte)0) throw new ModelEvaluationFailedException(); else return v; @@ -236,7 +232,7 @@ namespace Microsoft.Z3 public double Double(Z3_ast t) { var r = Eval(t, true); - return Native.Z3_get_numeral_double(Context.nCtx, r); + return Native.Z3_get_numeral_double(ntvContext.nCtx, r); } /// @@ -269,33 +265,28 @@ namespace Microsoft.Z3 { var r = Eval(t, true); // check that r is a sequence of store over a constant default array. - var updates = new List>(); + var updates = new Dictionary(); result = null; while (true) { - if (Context.GetAstKind(r) != Z3_ast_kind.Z3_APP_AST) + if (ntvContext.GetAstKind(r) != Z3_ast_kind.Z3_APP_AST) return false; - Z3_func_decl f = Context.GetAppDecl(r); - var kind = Context.GetDeclKind(f); + Z3_func_decl f = ntvContext.GetAppDecl(r); + var kind = ntvContext.GetDeclKind(f); if (kind == Z3_decl_kind.Z3_OP_CONST_ARRAY) { -#if false -// TODO result = new ArrayValue(); result.Else = r; result.Updates = updates.ToArray(); - result.Domain = updates.Select((x, y) => x).ToArray(); - result.Range = updates.Select((x, y) => y).ToArray(); -#endif + result.Domain = updates.Keys.ToArray(); + result.Range = updates.Values.ToArray(); return true; } else if (kind == Z3_decl_kind.Z3_OP_STORE) { -#if false - Debug.Assert(Context.NumArgs(r) == 3); - updates.Add(new KeyValuePair(Context.GetArg(r, 1), Context.GetArg(r, 2))); - r = Context.GetArg(r, 0); -#endif + Debug.Assert(ntvContext.GetNumArgs(r) == 3); + updates[ntvContext.GetAppArg(r, 1)] = ntvContext.GetAppArg(r, 2); + r = ntvContext.GetAppArg(r, 0); } else { @@ -308,7 +299,7 @@ namespace Microsoft.Z3 /// /// The number of uninterpreted sorts that the model has an interpretation for. /// - public uint NumSorts { get { return Native.Z3_model_get_num_sorts(Context.nCtx, NativeObject); } } + public uint NumSorts { get { return Native.Z3_model_get_num_sorts(ntvContext.nCtx, NativeObject); } } /// @@ -328,7 +319,7 @@ namespace Microsoft.Z3 uint n = NumSorts; Z3_sort[] res = new Z3_sort[n]; for (uint i = 0; i < n; i++) - res[i] = Native.Z3_model_get_sort(Context.nCtx, NativeObject, i); + res[i] = Native.Z3_model_get_sort(ntvContext.nCtx, NativeObject, i); return res; } } @@ -340,16 +331,16 @@ namespace Microsoft.Z3 /// A string representation of the model. public override string ToString() { - return Native.Z3_model_to_string(Context.nCtx, NativeObject); + return Native.Z3_model_to_string(ntvContext.nCtx, NativeObject); } IntPtr NativeObject; - NativeContext Context; + NativeContext ntvContext; internal NativeModel(NativeContext ctx, IntPtr obj) { - Context = ctx; + ntvContext = ctx; NativeObject = obj; Debug.Assert(ctx != null); Native.Z3_model_inc_ref(ctx.nCtx, obj); @@ -371,7 +362,7 @@ namespace Microsoft.Z3 { if (NativeObject != IntPtr.Zero) { - Native.Z3_model_dec_ref(Context.nCtx, NativeObject); + Native.Z3_model_dec_ref(ntvContext.nCtx, NativeObject); NativeObject = IntPtr.Zero; } GC.SuppressFinalize(this); diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs index 00110d550..40444804a 100644 --- a/src/api/dotnet/NativeSolver.cs +++ b/src/api/dotnet/NativeSolver.cs @@ -19,9 +19,9 @@ Notes: --*/ using System; +using System.Diagnostics; using System.Collections.Generic; using System.Linq; -using System.Diagnostics; namespace Microsoft.Z3 { From 676ba78600192c4f7dca1e59f226cb44bde96a37 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 13:10:02 -0800 Subject: [PATCH 098/258] fix else case: it is first argument of const array Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index 96eb13cd2..fc4205774 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -276,7 +276,7 @@ namespace Microsoft.Z3 if (kind == Z3_decl_kind.Z3_OP_CONST_ARRAY) { result = new ArrayValue(); - result.Else = r; + result.Else = ntvContext.GetAppArg(r, 0); result.Updates = updates.ToArray(); result.Domain = updates.Keys.ToArray(); result.Range = updates.Values.ToArray(); From 87e6f103c6883ea37da0198dc0a43e0b5db870d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 14:00:07 -0800 Subject: [PATCH 099/258] commenting Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeModel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index fc4205774..cfe5c691b 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -250,8 +250,14 @@ namespace Microsoft.Z3 /// public Z3_ast Else; + /// + /// Updates.Keys + /// public Z3_ast[] Domain; + /// + /// Updates.Range + /// public Z3_ast[] Range; } From 2b71d8bc0878ecb35b9b34ccbed558c21c4410f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 14:59:38 -0800 Subject: [PATCH 100/258] doc macros --- doc/website.dox.in | 1 - doc/z3api.cfg.in | 3 +-- doc/z3code.dox | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/website.dox.in b/doc/website.dox.in index 411520a17..69395492e 100644 --- a/doc/website.dox.in +++ b/doc/website.dox.in @@ -10,5 +10,4 @@ - \ref @C_API@ - \ref @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@ - - Try Z3 online at RiSE4Fun. */ diff --git a/doc/z3api.cfg.in b/doc/z3api.cfg.in index 9b7e61e34..41624b255 100644 --- a/doc/z3api.cfg.in +++ b/doc/z3api.cfg.in @@ -270,8 +270,7 @@ ALIASES = "beginfaq=
    " \ "emph{1}=\1" \ "extdoc{2}=\2" \ "nicebox{1}=
    \1
    " \ - "ccode{1}=\1" \ - "zframe=" + "ccode{1}=\1" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" diff --git a/doc/z3code.dox b/doc/z3code.dox index 205dd059b..b6a7fb088 100644 --- a/doc/z3code.dox +++ b/doc/z3code.dox @@ -64,8 +64,7 @@ ALIASES = "beginfaq=
      " \ "emph{1}=\1" \ "extdoc{2}=\2" \ "nicebox{1}=
      \1
      " \ - "ccode{1}=\1" \ - "zframe=" + "ccode{1}=\1" OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO From 3e51b69a9ab0a333b819a08d73b16b2cd64f7a2c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 15:03:02 -0800 Subject: [PATCH 101/258] no fun! Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1a35865c9..cd4aee24f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -12,8 +12,6 @@ Z3 is used in many applications such as: software/hardware verification and test constraint solving, analysis of hybrid systems, security, biology (in silico analysis), and geometrical problems. -Several online tutorials for Z3Py are available at: -http://rise4fun.com/Z3Py/tutorial/guide Please send feedback, comments and/or corrections on the Issue tracker for https://github.com/Z3prover/z3.git. Your comments are very valuable. @@ -103,9 +101,6 @@ def get_version(): def get_full_version(): return Z3_get_full_version() -# We use _z3_assert instead of the assert command because we want to -# produce nice error messages in Z3Py at rise4fun.com - def _z3_assert(cond, msg): if not cond: @@ -9009,7 +9004,7 @@ def prove(claim, show=False, **keywords): def _solve_html(*args, **keywords): - """Version of function `solve` used in RiSE4Fun.""" + """Version of function `solve` that renders HTML output.""" show = keywords.pop("show", False) s = Solver() s.set(**keywords) @@ -9033,7 +9028,7 @@ def _solve_html(*args, **keywords): def _solve_using_html(s, *args, **keywords): - """Version of function `solve_using` used in RiSE4Fun.""" + """Version of function `solve_using` that renders HTML.""" show = keywords.pop("show", False) if z3_debug(): _z3_assert(isinstance(s, Solver), "Solver object expected") @@ -9058,7 +9053,7 @@ def _solve_using_html(s, *args, **keywords): def _prove_html(claim, show=False, **keywords): - """Version of function `prove` used in RiSE4Fun.""" + """Version of function `prove` that renders HTML.""" if z3_debug(): _z3_assert(is_bool(claim), "Z3 Boolean expression expected") s = Solver() From b0c0f4d1f4437e05d581049fba5e20b238c9f2b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 15:07:45 -0800 Subject: [PATCH 102/258] fix #5876 Signed-off-by: Nikolaj Bjorner --- src/api/z3_optimization.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index 3cdacc46d..889db94ea 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -82,7 +82,7 @@ extern "C" { \param c - context \param o - optimization context \param a - formula - \param weight - a positive weight, penalty for violating soft constraint + \param weight - a penalty for violating soft constraint. Negative weights convert into rewards. \param id - optional identifier to group soft constraints \sa Z3_optimize_assert From 882fc31aea9068f9b64ade2dccf429b113c9cf61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Mar 2022 15:25:05 -0800 Subject: [PATCH 103/258] doc strings Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 49 ++++++++++++++++++++++++++++++++- src/api/dotnet/NativeModel.cs | 1 - 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 96e0487de..840c5b864 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -305,14 +305,39 @@ namespace Microsoft.Z3 #region Sort /// - /// Sorts return same ptr for subsequent calls + /// Integer Sort /// public Z3_sort IntSort => Native.Z3_mk_int_sort(nCtx); + /// + /// Boolean Sort + /// public Z3_sort BoolSort => Native.Z3_mk_bool_sort(nCtx); + /// + /// Real Sort + /// public Z3_sort RealSort => Native.Z3_mk_real_sort(nCtx); + /// + /// Bit-vector sort + /// + /// + /// public Z3_sort MkBvSort(uint size) => Native.Z3_mk_bv_sort(nCtx, size); + /// + /// Given an elemSort create a List of elemSort + /// The function returns the list sort, constructors, accessors and recognizers + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The list algebraic datatype + public Z3_sort MkListSort(string name, Z3_sort elemSort, out Z3_func_decl inil, out Z3_func_decl iisnil, out Z3_func_decl icons, out Z3_func_decl iiscons, @@ -410,6 +435,11 @@ namespace Microsoft.Z3 #endregion #region Symbol + /// + /// Create a symbol from a string + /// + /// + /// public Z3_symbol MkStringSymbol(string name) { Debug.Assert(!string.IsNullOrEmpty(name)); @@ -778,6 +808,18 @@ namespace Microsoft.Z3 return MkQuantifier(true, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); } + /// + /// Create an existential Quantifier. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// public Z3_ast MkExists(Z3_sort[] sorts, Z3_symbol[] names, Z3_ast body, uint weight = 1, Z3_ast[] patterns = null, Z3_ast[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { return MkQuantifier(false, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); @@ -1099,6 +1141,11 @@ namespace Microsoft.Z3 return args; } + /// + /// Retrieve number of arguments to a function application + /// + /// + /// public uint GetNumArgs(Z3_app app) { Debug.Assert(app != IntPtr.Zero); diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index cfe5c691b..eb6037199 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -299,7 +299,6 @@ namespace Microsoft.Z3 return false; } } - return true; } /// From e3568d5b47d976ebdd8f45f7816716549e28b3ef Mon Sep 17 00:00:00 2001 From: Lorenzo Veronese <310wert@gmail.com> Date: Mon, 7 Mar 2022 16:49:59 +0100 Subject: [PATCH 104/258] Handle additional cases in rule_properties::check_accessor (#5821) * Handle additional cases in rule_properties::check_accessor * Walk parents depth first in rule_properties::check_accessor --- src/muz/base/rule_properties.cpp | 93 ++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 991ca716e..7632a0c2f 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -210,19 +210,35 @@ bool rule_properties::check_accessor(app* n) { SASSERT(m_dt.is_datatype(s)); if (m_dt.get_datatype_constructors(s)->size() <= 1) return true; - func_decl* f = n->get_decl(); - func_decl * c = m_dt.get_accessor_constructor(f); + func_decl* c = m_dt.get_accessor_constructor(f); unsigned ut_size = m_rule->get_uninterpreted_tail_size(); unsigned t_size = m_rule->get_tail_size(); + ptr_vector ctors; + // add recognizer constructor to ctors + auto add_recognizer = [&](expr* r) { + if (!m_dt.is_recognizer(r)) + return; + if (n->get_arg(0) != to_app(r)->get_arg(0)) + return; + auto* c2 = m_dt.get_recognizer_constructor(to_app(r)->get_decl()); + if (c == c2) + return; + ctors.push_back(c2); + }; + auto add_not_recognizer = [&](expr* r) { + if (m.is_not(r, r)) + add_recognizer(r); + }; + + // t is a recognizer for n auto is_recognizer_base = [&](expr* t) { return m_dt.is_recognizer(t) && to_app(t)->get_arg(0) == n->get_arg(0) && m_dt.get_recognizer_constructor(to_app(t)->get_decl()) == c; }; - auto is_recognizer = [&](expr* t) { if (m.is_and(t)) for (expr* arg : *to_app(t)) @@ -231,43 +247,78 @@ bool rule_properties::check_accessor(app* n) { return is_recognizer_base(t); }; - - for (unsigned i = ut_size; i < t_size; ++i) - if (is_recognizer(m_rule->get_tail(i))) + for (unsigned i = ut_size; i < t_size; ++i) { + auto* tail = m_rule->get_tail(i); + if (is_recognizer(tail)) return true; - + add_not_recognizer(tail); + } // create parent use list for every sub-expression in the rule obj_map> use_list; for (unsigned i = ut_size; i < t_size; ++i) { app* t = m_rule->get_tail(i); use_list.insert_if_not_there(t, ptr_vector()).push_back(nullptr); // add marker for top-level expression. - for (expr* sub : subterms::all(expr_ref(t, m))) + for (expr* sub : subterms::all(expr_ref(t, m))) if (is_app(sub)) for (expr* arg : *to_app(sub)) use_list.insert_if_not_there(arg, ptr_vector()).push_back(sub); } - // walk parents of n to check that each path is guarded by a recognizer. - ptr_vector todo; - todo.push_back(n); - for (unsigned i = 0; i < todo.size(); ++i) { - expr* e = todo[i]; + // walk parents of n depth first to check that each path is guarded by a recognizer. + vector> todo; + todo.push_back({n, ctors.size(), false}); + while(!todo.empty()) { + auto [e, ctors_size, visited] = todo.back(); + if (visited) { + todo.pop_back(); + while (ctors.size() > ctors_size) ctors.pop_back(); + continue; + } + std::get<2>(todo.back()) = true; // set visited + if (!use_list.contains(e)) return false; for (expr* parent : use_list[e]) { - if (!parent) - return false; // top-level expressions are not guarded - if (is_recognizer(parent)) + if (!parent) { // top-level expression + // check if n is an unguarded "else" branch + ptr_vector diff; + for (auto* dtc : *m_dt.get_datatype_constructors(s)) + if (!ctors.contains(dtc)) + diff.push_back(dtc); + // the only unguarded constructor for s is c: + // all the others are guarded and we are in an "else" branch so the accessor is safe + if (diff.size() == 1 && diff[0] == c) + continue; + return false; // the accessor is not safe + } + if (is_recognizer(parent)) continue; - if (m.is_ite(parent) && to_app(parent)->get_arg(1) == e && is_recognizer(to_app(parent)->get_arg(0))) - continue; - todo.push_back(parent); + + expr *cnd, *thn, *els; + if (m.is_ite(parent, cnd, thn, els)) { + if (thn == e) { + if (is_recognizer(cnd) && els != e) + continue; // e is guarded + } + add_recognizer(cnd); + } + if (m.is_and(parent)) + for (expr* arg : *to_app(parent)) + add_not_recognizer(arg); + if (m.is_or(parent)) + for (expr* arg : *to_app(parent)) { + add_recognizer(arg); + // if one branch is not(recognizer) then the accessor is safe + if (m.is_not(arg, arg) && is_recognizer(arg)) + goto _continue; + } + todo.push_back({parent, ctors.size(), false}); + _continue:; } } - + return true; - } void rule_properties::operator()(app* n) { From 97c7ce63b535337fcd5c195ea2720546477c972e Mon Sep 17 00:00:00 2001 From: John Fleisher Date: Mon, 7 Mar 2022 15:55:30 -0500 Subject: [PATCH 105/258] Clean up build warnings (#5884) * Clean up warnings in compile for documentation notes * remove snk from local build Co-authored-by: jfleisher Co-authored-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 19 ++++++++++--------- src/api/dotnet/NativeModel.cs | 4 +++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index 840c5b864..f8513a7e6 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -308,25 +308,25 @@ namespace Microsoft.Z3 /// Integer Sort /// public Z3_sort IntSort => Native.Z3_mk_int_sort(nCtx); + /// - /// Boolean Sort + /// Returns the "singleton" BoolSort for this NativeContext /// public Z3_sort BoolSort => Native.Z3_mk_bool_sort(nCtx); + /// - /// Real Sort + /// Returns the "singleton" RealSort for this NativeContext /// public Z3_sort RealSort => Native.Z3_mk_real_sort(nCtx); + /// - /// Bit-vector sort + /// Returns the BvSort for size in this NativeContext /// - /// - /// public Z3_sort MkBvSort(uint size) => Native.Z3_mk_bv_sort(nCtx, size); /// - /// Given an elemSort create a List of elemSort - /// The function returns the list sort, constructors, accessors and recognizers + /// returns ListSort /// /// /// @@ -436,7 +436,7 @@ namespace Microsoft.Z3 #region Symbol /// - /// Create a symbol from a string + /// Return a ptr to symbol for string /// /// /// @@ -809,6 +809,7 @@ namespace Microsoft.Z3 } /// + /// Same as MkForAll but defaults to "forall" = false /// Create an existential Quantifier. /// /// @@ -1142,7 +1143,7 @@ namespace Microsoft.Z3 } /// - /// Retrieve number of arguments to a function application + /// Return number of arguments for app /// /// /// diff --git a/src/api/dotnet/NativeModel.cs b/src/api/dotnet/NativeModel.cs index eb6037199..3b9eb0950 100644 --- a/src/api/dotnet/NativeModel.cs +++ b/src/api/dotnet/NativeModel.cs @@ -251,12 +251,14 @@ namespace Microsoft.Z3 public Z3_ast Else; /// + /// Domain for array /// Updates.Keys /// public Z3_ast[] Domain; /// - /// Updates.Range + /// Range for array + /// Updates.Values /// public Z3_ast[] Range; } From e7ded9cdbd0bc78541996a16f2a4089cfd6602cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Mar 2022 08:34:12 -0800 Subject: [PATCH 106/258] update to 2022 --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4ed072d7c..cccf55a31 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -93,7 +93,7 @@ stages: - task: CmdLine@2 inputs: script: - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 & + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 & python scripts\mk_win_dist.py --x86-only --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk @@ -116,7 +116,7 @@ stages: - task: CmdLine@2 inputs: script: - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 & + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 & python scripts\mk_win_dist.py --x64-only --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk From 3293aeb7c765228487fb95f9fc974a5e48af5ecb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Mar 2022 08:35:54 -0800 Subject: [PATCH 107/258] na --- src/sat/smt/arith_solver.h | 3 +++ src/util/rational.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index d8405ea10..b11fafa43 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -419,6 +419,7 @@ namespace arith { void false_case_of_check_nla(const nla::lemma& l); void dbg_finalize_model(model& mdl); + public: solver(euf::solver& ctx, theory_id id); ~solver() override; @@ -426,6 +427,8 @@ namespace arith { void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override; void asserted(literal l) override; sat::check_result check() override; + void simplify() override; + void init_search() override; std::ostream& display(std::ostream& out) const override; std::ostream& display_justification(std::ostream& out, sat::ext_justification_idx idx) const override; diff --git a/src/util/rational.h b/src/util/rational.h index 3b8ee5649..9fadfb91f 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -173,6 +173,10 @@ public: return *this; } + rational& operator-=(int r) { + (*this) -= rational(r); + return *this; + } rational & operator*=(rational const & r) { m().mul(m_val, r.m_val, m_val); From c6f8ee33d4bdee9b56c65768304561c3c8989a19 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Mar 2022 08:36:14 -0800 Subject: [PATCH 108/258] na Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 98fd32591..0f242bd4d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -374,7 +374,7 @@ namespace sat { void set_eliminated(bool_var v, bool f) override; bool was_eliminated(literal l) const { return was_eliminated(l.var()); } void set_phase(literal l) override { if (l.var() < num_vars()) m_best_phase[l.var()] = m_phase[l.var()] = !l.sign(); } - bool_var get_phase(bool_var b) { return m_phase.get(b, false); } + bool get_phase(bool_var b) { return m_phase.get(b, false); } void move_to_front(bool_var b); unsigned scope_lvl() const { return m_scope_lvl; } unsigned search_lvl() const { return m_search_lvl; } From 1d224d1bcdc067e8424eaa1df41a63f88b18e210 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Mar 2022 08:51:00 -0800 Subject: [PATCH 109/258] na --- src/sat/smt/arith_solver.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index b11fafa43..a1d9c8629 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -427,8 +427,8 @@ namespace arith { void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override; void asserted(literal l) override; sat::check_result check() override; - void simplify() override; - void init_search() override; + void simplify() override {} + void init_search() override {} std::ostream& display(std::ostream& out) const override; std::ostream& display_justification(std::ostream& out, sat::ext_justification_idx idx) const override; From 43f76368268ea14f19cd187c6999ed2cc475f332 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 9 Mar 2022 12:46:41 +0000 Subject: [PATCH 110/258] remove some copies/moves --- src/ast/ast.cpp | 5 ++--- src/ast/bv_decl_plugin.cpp | 4 ++-- src/ast/datatype_decl_plugin.cpp | 8 ++++---- src/cmd_context/basic_cmds.cpp | 4 ++-- src/model/array_factory.cpp | 4 ++-- src/smt/theory_array_base.cpp | 4 ++-- src/util/gparams.cpp | 26 +++++++++++++------------- 7 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 23ad23329..65e2a5d1a 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -234,8 +234,7 @@ std::ostream& operator<<(std::ostream& out, sort_size const & ss) { // ----------------------------------- std::ostream & operator<<(std::ostream & out, sort_info const & info) { operator<<(out, static_cast(info)); - out << " :size " << info.get_num_elements(); - return out; + return out << " :size " << info.get_num_elements(); } // ----------------------------------- @@ -2237,7 +2236,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar std::ostringstream buffer; buffer << "Wrong number of arguments (" << num_args << ") passed to function " << mk_pp(decl, *this); - throw ast_exception(buffer.str()); + throw ast_exception(std::move(buffer).str()); } app * r = nullptr; if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) { diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 645088e3e..74002bb1b 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -886,8 +886,8 @@ app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const { } sort * bv_util::mk_sort(unsigned bv_size) { - parameter p[1] = { parameter(bv_size) }; - return m_manager.mk_sort(get_fid(), BV_SORT, 1, p); + parameter p(bv_size); + return m_manager.mk_sort(get_fid(), BV_SORT, 1, &p); } unsigned bv_util::get_int2bv_size(parameter const& p) { diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index ace0cb567..bc574fc1c 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -69,8 +69,8 @@ namespace datatype { domain.push_back(a->instantiate(ps)->get_range()); } sort_ref range = get_def().instantiate(ps); - parameter pas[1] = { parameter(name()) }; - return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, pas, domain.size(), domain.data(), range), m); + parameter pas(name()); + return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, &pas, domain.size(), domain.data(), range), m); } func_decl_ref constructor::instantiate(sort* dt) const { @@ -1052,8 +1052,8 @@ namespace datatype { func_decl * util::get_constructor_is(func_decl * con) { SASSERT(is_constructor(con)); sort * datatype = con->get_range(); - parameter ps[1] = { parameter(con)}; - return m.mk_func_decl(fid(), OP_DT_IS, 1, ps, 1, &datatype); + parameter ps(con); + return m.mk_func_decl(fid(), OP_DT_IS, 1, &ps, 1, &datatype); } func_decl * util::get_constructor_recognizer(func_decl * con) { diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 823f48e01..afe800af6 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -817,9 +817,9 @@ public: sort_ref range(ctx.m()); array_sort_args.push_back(m_f->get_range()); range = array_sort->instantiate(ctx.pm(), array_sort_args.size(), array_sort_args.data()); - parameter p[1] = { parameter(m_f) }; + parameter p(m_f); func_decl_ref new_map(ctx.m()); - new_map = ctx.m().mk_func_decl(get_array_fid(ctx), OP_ARRAY_MAP, 1, p, domain.size(), domain.data(), range.get()); + new_map = ctx.m().mk_func_decl(get_array_fid(ctx), OP_ARRAY_MAP, 1, &p, domain.size(), domain.data(), range.get()); if (new_map == 0) throw cmd_exception("invalid array map operator"); ctx.insert(m_name, new_map); diff --git a/src/model/array_factory.cpp b/src/model/array_factory.cpp index d3ec56d39..9c4aa816e 100644 --- a/src/model/array_factory.cpp +++ b/src/model/array_factory.cpp @@ -45,8 +45,8 @@ expr * array_factory::mk_array_interp(sort * s, func_interp * & fi) { func_decl * f = mk_aux_decl_for_array_sort(m_manager, s); fi = alloc(func_interp, m_manager, get_array_arity(s)); m_model.register_decl(f, fi); - parameter p[1] = { parameter(f) }; - expr * val = m_manager.mk_app(get_family_id(), OP_AS_ARRAY, 1, p); + parameter p(f); + expr * val = m_manager.mk_app(get_family_id(), OP_AS_ARRAY, 1, &p); register_value(val); return val; } diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 79b380671..9bc0b733f 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -958,8 +958,8 @@ namespace smt { fi->insert_entry(args.data(), result); } - parameter p[1] = { parameter(f) }; - return m.mk_app(m_fid, OP_AS_ARRAY, 1, p); + parameter p(f); + return m.mk_app(m_fid, OP_AS_ARRAY, 1, &p); } }; diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 25504eddd..28ce5a867 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -276,20 +276,20 @@ public: strm << "the parameter '" << param_name << "', invoke 'z3 -p' to obtain the new parameter list, and 'z3 -pp:" << new_name << "' for the full description of the parameter"; - throw exception(strm.str()); + throw exception(std::move(strm).str()); } else if (is_old_param_name(param_name)) { std::stringstream strm; strm << "unknown parameter '" << param_name << "', this is an old parameter name, invoke 'z3 -p' to obtain the new parameter list"; - throw default_exception(strm.str()); + throw default_exception(std::move(strm).str()); } else { std::stringstream strm; strm << "unknown parameter '" << param_name << "'\n"; strm << "Legal parameters are:\n"; d.display(strm, 2, false, false); - throw default_exception(strm.str()); + throw default_exception(std::move(strm).str()); } } else { @@ -298,7 +298,7 @@ public: strm << "at module '" << mod_name << "'\n"; strm << "Legal parameters are:\n"; d.display(strm, 2, false, false); - throw default_exception(strm.str()); + throw default_exception(std::move(strm).str()); } } @@ -312,7 +312,7 @@ public: if (!('0' <= *value && *value <= '9')) { strm << "Expected values for parameter " << name << " is an unsigned integer. It was given argument '" << _value << "'"; - throw default_exception(strm.str()); + throw default_exception(std::move(strm).str()); } } break; @@ -321,7 +321,7 @@ public: if (!('0' <= *value && *value <= '9') && *value != '.' && *value != '-' && *value != '/') { strm << "Expected values for parameter " << name << " is a double. It was given argument '" << _value << "'"; - throw default_exception(strm.str()); + throw default_exception(std::move(strm).str()); } } break; @@ -330,7 +330,7 @@ public: if (strcmp(value, "true") != 0 && strcmp(value, "false") != 0) { strm << "Expected values for parameter " << name << " are 'true' or 'false'. It was given argument '" << value << "'"; - throw default_exception(strm.str()); + throw default_exception(std::move(strm).str()); } break; default: @@ -368,7 +368,7 @@ public: if (mod_name[0]) { strm << " at module '" << mod_name << "'"; } - throw default_exception(strm.str()); + throw default_exception(std::move(strm).str()); } } else if (k == CPK_SYMBOL) { @@ -385,7 +385,7 @@ public: if (mod_name[0]) { strm << " at module '" << mod_name << "'"; } - throw exception(strm.str()); + throw exception(std::move(strm).str()); } } @@ -406,7 +406,7 @@ public: else { std::stringstream strm; strm << "invalid parameter, unknown module '" << m << "'"; - throw exception(strm.str()); + throw exception(std::move(strm).str()); } } } @@ -456,7 +456,7 @@ public: } std::stringstream strm; strm << "unknown module '" << m << "'"; - throw exception(strm.str()); + throw exception(std::move(strm).str()); } // unfortunately, params_ref is not thread safe @@ -523,7 +523,7 @@ public: if (!get_module_param_descr(module_name, d)) { std::stringstream strm; strm << "unknown module '" << module_name << "'"; - throw exception(strm.str()); + throw exception(std::move(strm).str()); } out << "[module] " << module_name; char const * descr = nullptr; @@ -548,7 +548,7 @@ public: if (!get_module_param_descr(m, d)) { std::stringstream strm; strm << "unknown module '" << m << "'"; - throw exception(strm.str()); + throw exception(std::move(strm).str()); } } if (!d->contains(sp)) From 8e18a94558b8a58dfa49ccf86c422fc2c3d9700e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Vran=C3=BD?= <82951+janvrany@users.noreply.github.com> Date: Wed, 9 Mar 2022 20:31:12 +0000 Subject: [PATCH 111/258] Update README with info about Smalltalk bindings (#5893) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 17d59558e..4849c33d8 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,11 @@ The Julia package [Z3.jl](https://github.com/ahumenberger/Z3.jl) wraps the C++ A A WebAssembly build with associated TypeScript typings is published on npm as [z3-solver](https://www.npmjs.com/package/z3-solver). Information about building these bindings can be found in [src/api/js](src/api/js). +### Smalltalk (``Pharo`` / ``Smalltalk/X``) + +Project [MachineArithmetic](https://github.com/shingarov/MachineArithmetic) provides Smalltalk interface +to Z3's C API. For more information, see [MachineArithmetic/README.md](https://github.com/shingarov/MachineArithmetic/blob/pure-z3/MachineArithmetic/README.md) + ## System Overview ![System Diagram](https://github.com/Z3Prover/doc/blob/master/programmingz3/images/Z3Overall.jpg) @@ -215,5 +220,6 @@ A WebAssembly build with associated TypeScript typings is published on npm as [z * C * OCaml * [Julia](https://github.com/ahumenberger/Z3.jl) +* [Smalltalk](https://github.com/shingarov/MachineArithmetic/blob/pure-z3/MachineArithmetic/README.md) (supports Pharo and Smalltalk/X) From f26c12a9ad08643484cafde9664dcdc5effaec8e Mon Sep 17 00:00:00 2001 From: Hari Govind V K Date: Wed, 9 Mar 2022 15:31:39 -0500 Subject: [PATCH 112/258] fix #5882. Use model true when inlining (#5892) --- src/muz/transforms/dl_mk_rule_inliner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index f7646b14a..d3ad54bd9 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -449,7 +449,7 @@ namespace datalog { } } if (modified) { - datalog::del_rule(m_mc, *r0, l_false); + datalog::del_rule(m_mc, *r0, l_true); } return modified; From 580012e19f4d7ed2227684e03c8b7183fb91498a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Mar 2022 09:44:56 -0800 Subject: [PATCH 113/258] fix #5894 expp is not implemented. This is the second time a fuzz bug reports it. Instead of closing the bug, just disable code path as fuzzers are not considering the comment from previous bug. --- src/sat/smt/arith_internalize.cpp | 2 +- src/smt/theory_lra.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 6f4963990..732cbfc6f 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -85,7 +85,7 @@ namespace arith { m_nla->settings().grobner_number_of_conflicts_to_report() = prms.arith_nl_grobner_cnfl_to_report(); m_nla->settings().grobner_quota() = prms.arith_nl_gr_q(); m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency(); - m_nla->settings().expensive_patching() = prms.arith_nl_expp(); + m_nla->settings().expensive_patching() = false; } } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 65e51fe03..cf1d73892 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -292,7 +292,7 @@ class theory_lra::imp { m_nla->settings().grobner_number_of_conflicts_to_report() = prms.arith_nl_grobner_cnfl_to_report(); m_nla->settings().grobner_quota() = prms.arith_nl_gr_q(); m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency(); - m_nla->settings().expensive_patching() = prms.arith_nl_expp(); + m_nla->settings().expensive_patching() = false; } } From 081c62d006306ea7db52b3949dc0e21f55fc458b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Mar 2022 17:08:49 -0800 Subject: [PATCH 114/258] allow range comparison for bit-vectors and int/real --- src/ast/char_decl_plugin.cpp | 9 +++++++++ src/ast/rewriter/seq_rewriter.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ast/char_decl_plugin.cpp b/src/ast/char_decl_plugin.cpp index 2ab4def9a..029312ba3 100644 --- a/src/ast/char_decl_plugin.cpp +++ b/src/ast/char_decl_plugin.cpp @@ -16,6 +16,7 @@ Author: --*/ #include "util/gparams.h" +#include "ast/bv_decl_plugin.h" #include "ast/char_decl_plugin.h" #include "ast/arith_decl_plugin.h" #include "ast/ast_pp.h" @@ -164,6 +165,14 @@ app* char_decl_plugin::mk_le(expr* a, expr* b) { unsigned v1 = 0, v2 = 0; if (a == b) return m_manager->mk_true(); + bv_util bv(*m_manager); + if (bv.is_bv(a)) + return bv.mk_ule(a, b); + arith_util arith(*m_manager); + if (arith.is_int_real(a)) + return arith.mk_le(a, b); + if (a->get_sort() != char_sort()) + throw default_exception("range comparison is only supported for bit-vectors, int, real and characters"); bool c1 = is_const_char(a, v1); bool c2 = is_const_char(b, v2); if (c1 && c2) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index b5f0e1475..02faebba5 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3128,8 +3128,8 @@ void seq_rewriter::mk_antimirov_deriv_rec(expr* e, expr* r, expr* path, expr_ref expr_ref range(m()); expr_ref psi(m().mk_false(), m()); if (str().is_unit_string(r1, c1) && str().is_unit_string(r2, c2)) { - SASSERT(u().is_char(c1)); - SASSERT(u().is_char(c2)); + // SASSERT(u().is_char(c1)); + // SASSERT(u().is_char(c2)); // case: c1 <= e <= c2 range = simplify_path(e, m().mk_and(u().mk_le(c1, e), u().mk_le(e, c2))); psi = simplify_path(e, m().mk_and(path, range)); From e839e18381b83c1171e34fa0955d6770564f379d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Mar 2022 17:31:17 -0800 Subject: [PATCH 115/258] minimal addition to rewrite bit-vector to character conversion using constant folding. --- src/ast/rewriter/CMakeLists.txt | 1 + src/ast/rewriter/char_rewriter.cpp | 62 ++++++++++++++++++++++++++++++ src/ast/rewriter/char_rewriter.h | 54 ++++++++++++++++++++++++++ src/ast/rewriter/th_rewriter.cpp | 5 +++ 4 files changed, 122 insertions(+) create mode 100644 src/ast/rewriter/char_rewriter.cpp create mode 100644 src/ast/rewriter/char_rewriter.h diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index d2b80ea9c..4bd6d07c4 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -9,6 +9,7 @@ z3_add_component(rewriter bv_elim.cpp bv_rewriter.cpp cached_var_subst.cpp + char_rewriter.cpp datatype_rewriter.cpp der.cpp distribute_forall.cpp diff --git a/src/ast/rewriter/char_rewriter.cpp b/src/ast/rewriter/char_rewriter.cpp new file mode 100644 index 000000000..5d730d7c6 --- /dev/null +++ b/src/ast/rewriter/char_rewriter.cpp @@ -0,0 +1,62 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + char_rewriter.cpp + +Abstract: + + Basic rewriting rules for character constraints + +Author: + + Nikolaj Bjorner (nbjorner) 2015-12-5 + +--*/ + +#include "util/debug.h" +#include "ast/rewriter/char_rewriter.h" +#include "ast/bv_decl_plugin.h" + +char_rewriter::char_rewriter(ast_manager& m): + m(m) { + m_char = static_cast(m.get_plugin(m.mk_family_id("char"))); +} + +family_id char_rewriter::get_fid() { + return m_char->get_family_id(); +} + +br_status char_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { + SASSERT(f->get_family_id() == get_fid()); + br_status st = BR_FAILED; + switch (f->get_decl_kind()) { + case OP_CHAR_CONST: + break; + case OP_CHAR_LE: + break; + case OP_CHAR_TO_INT: + break; + case OP_CHAR_TO_BV: + break; + case OP_CHAR_FROM_BV: + st = mk_char_from_bv(args[0], result); + break; + case OP_CHAR_IS_DIGIT: + break; + } + return st; +} + +br_status char_rewriter::mk_char_from_bv(expr* e, expr_ref& result) { + bv_util bv(m); + rational n; + if (bv.is_numeral(e, n) && n.is_unsigned()) { + if (n > m_char->max_char()) + return BR_FAILED; + result = m_char->mk_char(n.get_unsigned()); + return BR_DONE; + } + return BR_FAILED; +} diff --git a/src/ast/rewriter/char_rewriter.h b/src/ast/rewriter/char_rewriter.h new file mode 100644 index 000000000..f8e3b909e --- /dev/null +++ b/src/ast/rewriter/char_rewriter.h @@ -0,0 +1,54 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + char_rewriter.h + +Abstract: + + Basic rewriting rules for characters constraints. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-03-10 + +Notes: + +--*/ +#pragma once + +#include "ast/char_decl_plugin.h" +#include "ast/rewriter/rewriter_types.h" +#include "util/params.h" +#include "util/lbool.h" + + +/** + \brief Cheap rewrite rules for character constraints +*/ +class char_rewriter { + ast_manager& m; + char_decl_plugin* m_char; + + br_status mk_char_from_bv(expr* e, expr_ref& result); +public: + + char_rewriter(ast_manager& m); + + family_id get_fid(); + + br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); + + expr_ref mk_app(func_decl* f, expr_ref_vector const& args) { return mk_app(f, args.size(), args.data()); } + + expr_ref mk_app(func_decl* f, unsigned n, expr* const* args) { + expr_ref result(m); + if (f->get_family_id() != get_fid() || + BR_FAILED == mk_app_core(f, n, args, result)) + result = m.mk_app(f, n, args); + return result; + } + +}; + diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 3bc9c4ce1..22d6a83b7 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -21,6 +21,7 @@ Notes: #include "ast/rewriter/bool_rewriter.h" #include "ast/rewriter/arith_rewriter.h" #include "ast/rewriter/bv_rewriter.h" +#include "ast/rewriter/char_rewriter.h" #include "ast/rewriter/datatype_rewriter.h" #include "ast/rewriter/array_rewriter.h" #include "ast/rewriter/fpa_rewriter.h" @@ -48,6 +49,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { dl_rewriter m_dl_rw; pb_rewriter m_pb_rw; seq_rewriter m_seq_rw; + char_rewriter m_char_rw; recfun_rewriter m_rec_rw; arith_util m_a_util; bv_util m_bv_util; @@ -247,6 +249,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return m_pb_rw.mk_app_core(f, num, args, result); if (fid == m_seq_rw.get_fid()) return m_seq_rw.mk_app_core(f, num, args, result); + if (fid == m_char_rw.get_fid()) + return m_char_rw.mk_app_core(f, num, args, result); if (fid == m_rec_rw.get_fid()) return m_rec_rw.mk_app_core(f, num, args, result); return BR_FAILED; @@ -802,6 +806,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { m_dl_rw(m), m_pb_rw(m), m_seq_rw(m), + m_char_rw(m), m_rec_rw(m), m_a_util(m), m_bv_util(m), From c51ca86203e999dd86ce505d36e5d706ce0f67d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Mar 2022 17:39:40 -0800 Subject: [PATCH 116/258] add another constant folding case --- src/ast/rewriter/char_rewriter.cpp | 17 ++++++++++++++--- src/ast/rewriter/char_rewriter.h | 3 +++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/char_rewriter.cpp b/src/ast/rewriter/char_rewriter.cpp index 5d730d7c6..14b86773a 100644 --- a/src/ast/rewriter/char_rewriter.cpp +++ b/src/ast/rewriter/char_rewriter.cpp @@ -18,6 +18,8 @@ Author: #include "util/debug.h" #include "ast/rewriter/char_rewriter.h" #include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" + char_rewriter::char_rewriter(ast_manager& m): m(m) { @@ -37,6 +39,7 @@ br_status char_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * co case OP_CHAR_LE: break; case OP_CHAR_TO_INT: + st = mk_char_to_int(args[0], result); break; case OP_CHAR_TO_BV: break; @@ -52,11 +55,19 @@ br_status char_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * co br_status char_rewriter::mk_char_from_bv(expr* e, expr_ref& result) { bv_util bv(m); rational n; - if (bv.is_numeral(e, n) && n.is_unsigned()) { - if (n > m_char->max_char()) - return BR_FAILED; + if (bv.is_numeral(e, n) && n.is_unsigned() && n <= m_char->max_char()) { result = m_char->mk_char(n.get_unsigned()); return BR_DONE; } return BR_FAILED; } + +br_status char_rewriter::mk_char_to_int(expr* e, expr_ref& result) { + unsigned n = 0; + if (m_char->is_const_char(e, n)) { + arith_util arith(m); + result = arith.mk_int(n); + return BR_DONE; + } + return BR_FAILED; +} diff --git a/src/ast/rewriter/char_rewriter.h b/src/ast/rewriter/char_rewriter.h index f8e3b909e..f67695bd8 100644 --- a/src/ast/rewriter/char_rewriter.h +++ b/src/ast/rewriter/char_rewriter.h @@ -32,6 +32,9 @@ class char_rewriter { char_decl_plugin* m_char; br_status mk_char_from_bv(expr* e, expr_ref& result); + + br_status mk_char_to_int(expr* e, expr_ref& result); + public: char_rewriter(ast_manager& m); From 545341e69999ceca585f3dacc08d5c6b6f096edc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Mar 2022 09:17:03 -0800 Subject: [PATCH 117/258] fix #5895 --- src/smt/old_interval.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/old_interval.cpp b/src/smt/old_interval.cpp index efdb78754..e719f7e2b 100644 --- a/src/smt/old_interval.cpp +++ b/src/smt/old_interval.cpp @@ -292,7 +292,7 @@ v_dependency * interval::join_opt(v_dependency * d1, v_dependency * d2, v_depend } interval & interval::operator*=(interval const & other) { -#if Z3DEBUG || _TRACE +#if defined(Z3DEBUG) || defined(_TRACE) bool contains_zero1 = contains_zero(); bool contains_zero2 = other.contains_zero(); #endif From 313b87f3c68f849b1747e0f6eb5cf89ff8e8c9b5 Mon Sep 17 00:00:00 2001 From: Chaoqi Zhang Date: Tue, 15 Mar 2022 00:30:08 +0800 Subject: [PATCH 118/258] doc: update readme (#5898) add the command to `mkdir build` first --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4849c33d8..44e643662 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ python scripts/mk_make.py -x then: ```bash -cd build +mkdir build && cd build nmake ``` @@ -54,7 +54,7 @@ Execute: ```bash python scripts/mk_make.py -cd build +mkdir build && cd build make sudo make install ``` @@ -86,7 +86,7 @@ the ``--prefix=`` command line option to change the install prefix. For example: ```bash python scripts/mk_make.py --prefix=/home/leo -cd build +mkdir build && cd build make make install ``` From 706d7ea8936074cad3b49fb15da50a5deb8f386c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Mar 2022 16:00:56 -0700 Subject: [PATCH 119/258] native context uses legacy mk_context Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/NativeContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/NativeContext.cs b/src/api/dotnet/NativeContext.cs index f8513a7e6..9f285ec84 100644 --- a/src/api/dotnet/NativeContext.cs +++ b/src/api/dotnet/NativeContext.cs @@ -69,7 +69,7 @@ namespace Microsoft.Z3 IntPtr cfg = Native.Z3_mk_config(); foreach (KeyValuePair kv in settings) Native.Z3_set_param_value(cfg, kv.Key, kv.Value); - m_ctx = Native.Z3_mk_context_rc(cfg); + m_ctx = Native.Z3_mk_context(cfg); Native.Z3_del_config(cfg); InitContext(); } From e1929ca9b979697747e823180c3611af7f0b9ac0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Mar 2022 19:18:33 -0700 Subject: [PATCH 120/258] add regex power to API and for Java per request Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 11 +++++++++++ src/api/java/Context.java | 8 ++++++++ src/api/z3_api.h | 7 +++++++ src/ast/seq_decl_plugin.cpp | 6 ++++++ src/ast/seq_decl_plugin.h | 1 + 5 files changed, 33 insertions(+) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index a7c42df4f..d64589cde 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -315,6 +315,17 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast r, unsigned n) { + Z3_TRY; + LOG_Z3_mk_re_power(c, r, n); + RESET_ERROR_CODE(); + app* a = mk_c(c)->sutil().re.mk_power(to_expr(r), n); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(nullptr); + } + + MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP); MK_UNARY(Z3_mk_re_star, mk_c(c)->get_seq_fid(), OP_RE_STAR, SKIP); MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP); diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 466047c16..62ffcd585 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2200,6 +2200,14 @@ public class Context implements AutoCloseable { return (ReExpr) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject())); } + /** + * Create power regular expression. + */ + public ReExpr mkLoop(Expr> re, int n) + { + return (ReExpr) Expr.create(this, Native.mkRePower(nCtx(), re.getNativeObject(), n)); + } + /** * Take the lower and upper-bounded Kleene star of a regular expression. */ diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d8c817933..d7dd0a332 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3821,6 +3821,13 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi); + /** + \brief Create a power regular expression. + + def_API('Z3_mk_re_power', AST, (_in(CONTEXT), _in(AST), _in(UINT))) + */ + Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast, unsigned n); + /** \brief Create the intersection of the regular languages. diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 091f77f5c..f4cf2ecaa 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -1053,6 +1053,12 @@ sort* seq_util::rex::to_seq(sort* re) { return to_sort(re->get_parameter(0).get_ast()); } +app* seq_util::rex::mk_power(expr* r, unsigned n) { + parameter param(n); + return m.mk_app(m_fid, OP_RE_POWER, 1, ¶m, 1, &r); +} + + app* seq_util::rex::mk_loop(expr* r, unsigned lo) { parameter param(lo); return m.mk_app(m_fid, OP_RE_LOOP, 1, ¶m, 1, &r); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 9c76298b0..ddde7fa6a 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -502,6 +502,7 @@ public: app* mk_star(expr* r) { return m.mk_app(m_fid, OP_RE_STAR, r); } app* mk_plus(expr* r) { return m.mk_app(m_fid, OP_RE_PLUS, r); } app* mk_opt(expr* r) { return m.mk_app(m_fid, OP_RE_OPTION, r); } + app* mk_power(expr* r, unsigned n); app* mk_loop(expr* r, unsigned lo); app* mk_loop(expr* r, unsigned lo, unsigned hi); expr* mk_loop_proper(expr* r, unsigned lo, unsigned hi); From cb9dcb799f4d2e6faf2a71f97c7dc0ca8336fd76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Mar 2022 06:17:31 -0700 Subject: [PATCH 121/258] add regex power to API and for Java per request Signed-off-by: Nikolaj Bjorner --- src/api/java/Context.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 62ffcd585..7b5f8a936 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2203,7 +2203,7 @@ public class Context implements AutoCloseable { /** * Create power regular expression. */ - public ReExpr mkLoop(Expr> re, int n) + public ReExpr mkPower(Expr> re, int n) { return (ReExpr) Expr.create(this, Native.mkRePower(nCtx(), re.getNativeObject(), n)); } From cd5e114ed3bfb32e3ed20861a6593a5d45948cc3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Mar 2022 07:24:33 -0700 Subject: [PATCH 122/258] call dispose on sorts #5900 Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 3432c8028..056a361fe 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -4927,6 +4927,10 @@ namespace Microsoft.Z3 Fixedpoint_DRQ.Clear(this); Optimize_DRQ.Clear(this); + if (m_boolSort != null) m_boolSort.Dispose(); + if (m_intSort != null) m_intSort.Dispose(); + if (m_realSort != null) m_realSort.Dispose(); + if (m_stringSort != null) m_stringSort.Dispose(); m_boolSort = null; m_intSort = null; m_realSort = null; From a1517251dd05cf71777708e5f1574cb57aef93d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Mar 2022 07:28:05 -0700 Subject: [PATCH 123/258] call dispose on sorts #5900, missing charSort Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 056a361fe..4b865c0ba 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -4931,10 +4931,12 @@ namespace Microsoft.Z3 if (m_intSort != null) m_intSort.Dispose(); if (m_realSort != null) m_realSort.Dispose(); if (m_stringSort != null) m_stringSort.Dispose(); + if (m_charSort != null) m_charSort.Dispose(); m_boolSort = null; m_intSort = null; m_realSort = null; m_stringSort = null; + m_charSort = null; if (refCount == 0 && m_ctx != IntPtr.Zero) { m_n_err_handler = null; From 3d87d86c2825437780167ae6ff8f5b203f15ee7f Mon Sep 17 00:00:00 2001 From: Han Gao Date: Wed, 16 Mar 2022 22:30:20 +0800 Subject: [PATCH 124/258] github action: add riscv64/aarch64/powerpc64 cross compile (#5897) * github action: add riscv64/aarch64/powerpc64 cross compile Signed-off-by: Han Gao * fix: build on non-x86 platform Signed-off-by: Revy --- .github/workflows/cross-build.yml | 30 ++++++++++++++++++++++++++++++ CMakeLists.txt | 5 +++++ cmake/check_link_atomic.cmake | 23 +++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 .github/workflows/cross-build.yml create mode 100644 cmake/check_link_atomic.cmake diff --git a/.github/workflows/cross-build.yml b/.github/workflows/cross-build.yml new file mode 100644 index 000000000..40932aac2 --- /dev/null +++ b/.github/workflows/cross-build.yml @@ -0,0 +1,30 @@ +name: build + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + container: ubuntu:jammy + + strategy: + fail-fast: false + matrix: + arch: [ aarch64, riscv64, powerpc64 ] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install cross build tools + run: apt update && apt install -y ninja-build cmake python3 g++-11-${{ matrix.arch }}-linux-gnu + env: + DEBIAN_FRONTEND: noninteractive + + - name: Configure CMake and build + run: | + mkdir build && cd build + cmake -DCMAKE_CXX_COMPILER=${{ matrix.arch }}-linux-gnu-g++-11 ../ + make -j$(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index be300607d..477410ba8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -431,6 +431,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") string(APPEND CMAKE_SHARED_LINKER_FLAGS " /RELEASE") endif() +################################################################################ +# Check atomic linking as needed +################################################################################ +include(${PROJECT_SOURCE_DIR}/cmake/check_link_atomic.cmake) + ################################################################################ # Report default CMake flags ################################################################################ diff --git a/cmake/check_link_atomic.cmake b/cmake/check_link_atomic.cmake new file mode 100644 index 000000000..d462191a0 --- /dev/null +++ b/cmake/check_link_atomic.cmake @@ -0,0 +1,23 @@ +set(ATOMIC_TEST_SOURCE " +#include +std::atomic x; +std::atomic y; +std::atomic z; +std::atomic w; +int main() { + ++z; + ++y; + ++w; + return ++x; +}") +CHECK_CXX_SOURCE_COMPILES("${ATOMIC_TEST_SOURCE}" BUILTIN_ATOMIC) +if (NOT BUILTIN_ATOMIC) + set(CMAKE_REQUIRED_LIBRARIES atomic) + CHECK_CXX_SOURCE_COMPILES("${ATOMIC_TEST_SOURCE}" ATOMICS_REQUIRE_LIBATOMIC) + unset(CMAKE_REQUIRED_LIBRARIES) + if (ATOMICS_REQUIRE_LIBATOMIC) + list(APPEND Z3_DEPENDENT_LIBS atomic) + else() + message(FATAL_ERROR "Host compiler must support std::atomic!") + endif() +endif() From 6c4780a8459e515b39899caf85e912166b7850b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Mar 2022 07:32:05 -0700 Subject: [PATCH 125/258] Update cross-build.yml --- .github/workflows/cross-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cross-build.yml b/.github/workflows/cross-build.yml index 40932aac2..5efd00329 100644 --- a/.github/workflows/cross-build.yml +++ b/.github/workflows/cross-build.yml @@ -1,4 +1,4 @@ -name: build +name: RISC V and PowerPC 64 on: push: From 0b230ee703de998aaca649058f8c812b719d3af8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Mar 2022 16:29:54 -0700 Subject: [PATCH 126/258] move some functions to using var pattern #5900 Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 66 ++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 4b865c0ba..342723663 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -202,8 +202,8 @@ namespace Microsoft.Z3 ///
public UninterpretedSort MkUninterpretedSort(string str) { - - return MkUninterpretedSort(MkSymbol(str)); + using var sym = MkSymbol(str); + return MkUninterpretedSort(sym); } /// @@ -312,8 +312,9 @@ namespace Microsoft.Z3 public EnumSort MkEnumSort(string name, params string[] enumNames) { Debug.Assert(enumNames != null); - - return new EnumSort(this, MkSymbol(name), MkSymbols(enumNames)); + using var sname = MkSymbol(name); + using var snames = MkSymbols(enumNames); + return new EnumSort(this, sname, snames); } /// @@ -337,7 +338,8 @@ namespace Microsoft.Z3 Debug.Assert(elemSort != null); CheckContextMatch(elemSort); - return new ListSort(this, MkSymbol(name), elemSort); + using var sname = MkSymbol(name); + return new ListSort(this, sname, elemSort); } /// @@ -364,8 +366,8 @@ namespace Microsoft.Z3 /// The size of the sort public FiniteDomainSort MkFiniteDomainSort(string name, ulong size) { - - return new FiniteDomainSort(this, MkSymbol(name), size); + using var sname = MkSymbol(name); + return new FiniteDomainSort(this, sname, size); } @@ -399,8 +401,10 @@ namespace Microsoft.Z3 /// public Constructor MkConstructor(string name, string recognizer, string[] fieldNames = null, Sort[] sorts = null, uint[] sortRefs = null) { - - return new Constructor(this, MkSymbol(name), MkSymbol(recognizer), MkSymbols(fieldNames), sorts, sortRefs); + using var sname = MkSymbol(name); + using var srecognizer = MkSymbol(recognizer); + using var sfieldNames = MkSymbols(fieldNames); + return new Constructor(this, sname, srecognizer, sfieldNames, sorts, sortRefs); } /// @@ -427,7 +431,8 @@ namespace Microsoft.Z3 Debug.Assert(constructors.All(c => c != null)); CheckContextMatch(constructors); - return new DatatypeSort(this, MkSymbol(name), constructors); + using var sname = MkSymbol(name); + return new DatatypeSort(this, sname, constructors); } /// @@ -475,8 +480,8 @@ namespace Microsoft.Z3 Debug.Assert(names.Length == c.Length); //Debug.Assert(Contract.ForAll(0, c.Length, j => c[j] != null)); //Debug.Assert(names.All(name => name != null)); - - return MkDatatypeSorts(MkSymbols(names), c); + var snames = MkSymbols(names); + return MkDatatypeSorts(snames, c); } /// @@ -537,7 +542,8 @@ namespace Microsoft.Z3 CheckContextMatch(domain); CheckContextMatch(range); - return new FuncDecl(this, MkSymbol(name), domain, range); + using var sname = MkSymbol(name); + return new FuncDecl(this, sname, domain, range); } /// @@ -550,7 +556,8 @@ namespace Microsoft.Z3 CheckContextMatch(domain); CheckContextMatch(range); - return new FuncDecl(this, MkSymbol(name), domain, range, true); + using var sname = MkSymbol(name); + return new FuncDecl(this, sname, domain, range, true); } /// @@ -578,8 +585,9 @@ namespace Microsoft.Z3 CheckContextMatch(domain); CheckContextMatch(range); + using var sname = MkSymbol(name); Sort[] q = new Sort[] { domain }; - return new FuncDecl(this, MkSymbol(name), q, range); + return new FuncDecl(this, sname, q, range); } /// @@ -618,7 +626,8 @@ namespace Microsoft.Z3 Debug.Assert(range != null); CheckContextMatch(range); - return new FuncDecl(this, MkSymbol(name), null, range); + using var sname = MkSymbol(name); + return new FuncDecl(this, sname, null, range); } /// @@ -685,8 +694,8 @@ namespace Microsoft.Z3 public Expr MkConst(string name, Sort range) { Debug.Assert(range != null); - - return MkConst(MkSymbol(name), range); + using var sname = MkSymbol(name); + return MkConst(sname, range); } /// @@ -727,8 +736,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBoolConst(string name) { - - return (BoolExpr)MkConst(MkSymbol(name), BoolSort); + using var sname = MkSymbol(name); + return (BoolExpr)MkConst(sname, BoolSort); } /// @@ -776,8 +785,8 @@ namespace Microsoft.Z3 public BitVecExpr MkBVConst(Symbol name, uint size) { Debug.Assert(name != null); - - return (BitVecExpr)MkConst(name, MkBitVecSort(size)); + using var sort = MkBitVecSort(size); + return (BitVecExpr)MkConst(name, sort); } /// @@ -785,8 +794,8 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVConst(string name, uint size) { - - return (BitVecExpr)MkConst(name, MkBitVecSort(size)); + using var sort = MkBitVecSort(size); + return (BitVecExpr)MkConst(name, sort); } #endregion @@ -2042,8 +2051,9 @@ namespace Microsoft.Z3 { Debug.Assert(domain != null); Debug.Assert(range != null); - - return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range)); + using var sort = MkArraySort(domain, range); + using var sname = MkSymbol(name); + return (ArrayExpr)MkConst(sname, sort); } @@ -3837,8 +3847,8 @@ namespace Microsoft.Z3 /// public Solver MkSolver(string logic) { - - return MkSolver(MkSymbol(logic)); + using var slogic = MkSymbol(logic); + return MkSolver(slogic); } /// From bdf7de170394b920711d033cf14af97708f783a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Vran=C3=BD?= <82951+janvrany@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:28:03 +0000 Subject: [PATCH 127/258] Care for root index being undefine while calling Z3_algebraic_get_i() (#5888) In some cases, Z3_algebraic_get_i() returned 0. For example, in the following Python snippet, the last assert would fail: import z3 x = z3.Real('x') s = z3.Solver() s.add( (x * x) - 2 == 0, x <= 0) s.check() val_x = s.model().get_interp(x) assert val_x.index() == 1 The problem was that `algebraic_numbers::manager::imp::get_i()` did not check whether the root index was properly initialized. This commit fixes this issue by checking whether root index is initialized the same way various other routines do. Fixes issue #5807. Signed-off-by: Jan Vrany --- src/math/polynomial/algebraic_numbers.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 5244de82c..57ce00e2c 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -2013,6 +2013,11 @@ namespace algebraic_numbers { } else { algebraic_cell * c = a.to_algebraic(); + if (c->m_i == 0) { + // undefined + c->m_i = upm().get_root_id(c->m_p_sz, c->m_p, lower(c)) + 1; + } + SASSERT(c->m_i > 0); return c->m_i; } } From 4e0a2f596820cd4992aed569749e25fcfbaff307 Mon Sep 17 00:00:00 2001 From: Matt Thornton Date: Thu, 17 Mar 2022 15:08:05 +0000 Subject: [PATCH 128/258] Dispose of intermediate Z3Objects created in dotnet api. (#5901) * Dispose of intermediate Z3Objects created in dotnet api. * Set C# LangVersion to 8.0. * Fix build errors. * Fix warning about empty using statement. * Fix Xor to only dispose of objects that it creates internally. --- scripts/mk_util.py | 1 + src/api/dotnet/ASTMap.cs | 2 +- src/api/dotnet/ArithExpr.cs | 205 +++++++++++++++++++++----- src/api/dotnet/Context.cs | 165 ++++++++++++--------- src/api/dotnet/DatatypeSort.cs | 2 +- src/api/dotnet/EnumSort.cs | 3 +- src/api/dotnet/Fixedpoint.cs | 8 +- src/api/dotnet/Goal.cs | 4 +- src/api/dotnet/Microsoft.Z3.csproj.in | 2 + src/api/dotnet/Model.cs | 7 +- src/api/dotnet/Optimize.cs | 12 +- src/api/dotnet/RatNum.cs | 4 +- src/api/dotnet/Solver.cs | 87 ++++++++--- 13 files changed, 360 insertions(+), 142 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index ce34ac7eb..1fca64f29 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1682,6 +1682,7 @@ class DotNetDLLComponent(Component): netstandard1.4 + 8.0 $(DefineConstants);DOTNET_CORE portable Microsoft.Z3 diff --git a/src/api/dotnet/ASTMap.cs b/src/api/dotnet/ASTMap.cs index f678f71c3..0dde04411 100644 --- a/src/api/dotnet/ASTMap.cs +++ b/src/api/dotnet/ASTMap.cs @@ -100,7 +100,7 @@ namespace Microsoft.Z3 { get { - ASTVector res = new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject)); + using ASTVector res = new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject)); return res.ToArray(); } } diff --git a/src/api/dotnet/ArithExpr.cs b/src/api/dotnet/ArithExpr.cs index 53b9db21d..bd1aedc80 100644 --- a/src/api/dotnet/ArithExpr.cs +++ b/src/api/dotnet/ArithExpr.cs @@ -22,7 +22,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; - namespace Microsoft.Z3 { /// @@ -41,24 +40,48 @@ namespace Microsoft.Z3 #region Operators - private static ArithExpr MkNum(ArithExpr e, int i) { return (ArithExpr)e.Context.MkNumeral(i, e.Context.MkIntSort()); } + private static ArithExpr MkNum(ArithExpr e, int i) + { + using var sort = e.Context.MkIntSort(); + return (ArithExpr)e.Context.MkNumeral(i, sort); + } - private static ArithExpr MkNum(ArithExpr e, double d) { return (ArithExpr)e.Context.MkNumeral(d.ToString(), e.Context.MkRealSort()); } + private static ArithExpr MkNum(ArithExpr e, double d) + { + using var sort = e.Context.MkRealSort(); + return (ArithExpr)e.Context.MkNumeral(d.ToString(), sort); + } /// Operator overloading for arithmetical division operator (over reals) public static ArithExpr operator /(ArithExpr a, ArithExpr b) { return a.Context.MkDiv(a, b); } /// Operator overloading for arithmetical operator - public static ArithExpr operator /(ArithExpr a, int b) { return a / MkNum(a, b); } + public static ArithExpr operator /(ArithExpr a, int b) + { + using var denominator = MkNum(a, b); + return a / denominator; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator /(ArithExpr a, double b) { return a / MkNum(a, b); } + public static ArithExpr operator /(ArithExpr a, double b) + { + using var denominator = MkNum(a, b); + return a / denominator; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator /(int a, ArithExpr b) { return MkNum(b, a) / b; } + public static ArithExpr operator /(int a, ArithExpr b) + { + using var numerator = MkNum(b, a); + return numerator / b; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator /(double a, ArithExpr b) { return MkNum(b, a) / b; } + public static ArithExpr operator /(double a, ArithExpr b) + { + using var numerator = MkNum(b, a); + return numerator / b; + } /// Operator overloading for arithmetical operator public static ArithExpr operator -(ArithExpr a) { return a.Context.MkUnaryMinus(a); } @@ -67,106 +90,218 @@ namespace Microsoft.Z3 public static ArithExpr operator -(ArithExpr a, ArithExpr b) { return a.Context.MkSub(a, b); } /// Operator overloading for arithmetical operator - public static ArithExpr operator -(ArithExpr a, int b) { return a - MkNum(a, b); } + public static ArithExpr operator -(ArithExpr a, int b) + { + using var rhs = MkNum(a, b); + return a - rhs; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator -(ArithExpr a, double b) { return a - MkNum(a, b); } + public static ArithExpr operator -(ArithExpr a, double b) + { + using var rhs = MkNum(a, b); + return a - rhs; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator -(int a, ArithExpr b) { return MkNum(b, a) - b; } + public static ArithExpr operator -(int a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs - b; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator -(double a, ArithExpr b) { return MkNum(b, a) - b; } + public static ArithExpr operator -(double a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs - b; + } /// Operator overloading for arithmetical operator public static ArithExpr operator +(ArithExpr a, ArithExpr b) { return a.Context.MkAdd(a, b); } /// Operator overloading for arithmetical operator - public static ArithExpr operator +(ArithExpr a, int b) { return a + MkNum(a, b); } + public static ArithExpr operator +(ArithExpr a, int b) + { + using var rhs = MkNum(a, b); + return a + rhs; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator +(ArithExpr a, double b) { return a + MkNum(a, b); } + public static ArithExpr operator +(ArithExpr a, double b) + { + using var rhs = MkNum(a, b); + return a + rhs; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator +(int a, ArithExpr b) { return MkNum(b, a) + b; } + public static ArithExpr operator +(int a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs + b; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator +(double a, ArithExpr b) { return MkNum(b, a) + b; } + public static ArithExpr operator +(double a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs + b; + } /// Operator overloading for arithmetical operator public static ArithExpr operator *(ArithExpr a, ArithExpr b) { return a.Context.MkMul(a, b); } /// Operator overloading for arithmetical operator - public static ArithExpr operator *(ArithExpr a, int b) { return a * MkNum(a, b); } + public static ArithExpr operator *(ArithExpr a, int b) + { + using var rhs = MkNum(a, b); + return a * rhs; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator *(ArithExpr a, double b) { return a * MkNum(a, b); } + public static ArithExpr operator *(ArithExpr a, double b) + { + using var rhs = MkNum(a, b); + return a * rhs; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator *(int a, ArithExpr b) { return MkNum(b, a) * b; } + public static ArithExpr operator *(int a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs * b; + } /// Operator overloading for arithmetical operator - public static ArithExpr operator *(double a, ArithExpr b) { return MkNum(b, a) * b; } + public static ArithExpr operator *(double a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs * b; + } /// Operator overloading for arithmetical operator public static BoolExpr operator <=(ArithExpr a, ArithExpr b) { return a.Context.MkLe(a, b); } /// Operator overloading for arithmetical operator - public static BoolExpr operator <=(ArithExpr a, int b) { return a <= MkNum(a, b); } + public static BoolExpr operator <=(ArithExpr a, int b) + { + using var rhs = MkNum(a, b); + return a <= rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator <=(ArithExpr a, double b) { return a <= MkNum(a, b); } + public static BoolExpr operator <=(ArithExpr a, double b) + { + using var rhs = MkNum(a, b); + return a <= rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator <=(int a, ArithExpr b) { return MkNum(b, a) <= b; } + public static BoolExpr operator <=(int a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs <= b; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator <=(double a, ArithExpr b) { return MkNum(b, a) <= b; } + public static BoolExpr operator <=(double a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs <= b; + } /// Operator overloading for arithmetical operator public static BoolExpr operator <(ArithExpr a, ArithExpr b) { return a.Context.MkLt(a, b); } /// Operator overloading for arithmetical operator - public static BoolExpr operator <(ArithExpr a, int b) { return a < MkNum(a, b); } + public static BoolExpr operator <(ArithExpr a, int b) + { + using var rhs = MkNum(a, b); + return a < rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator <(ArithExpr a, double b) { return a < MkNum(a, b); } + public static BoolExpr operator <(ArithExpr a, double b) + { + using var rhs = MkNum(a, b); + return a < rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator <(int a, ArithExpr b) { return MkNum(b, a) < b; } + public static BoolExpr operator <(int a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs < b; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator <(double a, ArithExpr b) { return MkNum(b, a) < b; } + public static BoolExpr operator <(double a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs < b; + } /// Operator overloading for arithmetical operator public static BoolExpr operator >(ArithExpr a, ArithExpr b) { return a.Context.MkGt(a, b); } /// Operator overloading for arithmetical operator - public static BoolExpr operator >(ArithExpr a, int b) { return a > MkNum(a, b); } + public static BoolExpr operator >(ArithExpr a, int b) + { + using var rhs = MkNum(a, b); + return a > rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator >(ArithExpr a, double b) { return a > MkNum(a, b); } + public static BoolExpr operator >(ArithExpr a, double b) + { + using var rhs = MkNum(a, b); + return a > rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator >(int a, ArithExpr b) { return MkNum(b, a) > b; } + public static BoolExpr operator >(int a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs > b; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator >(double a, ArithExpr b) { return MkNum(b, a) > b; } + public static BoolExpr operator >(double a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs > b; + } /// Operator overloading for arithmetical operator public static BoolExpr operator >=(ArithExpr a, ArithExpr b) { return a.Context.MkGe(a, b); } /// Operator overloading for arithmetical operator - public static BoolExpr operator >=(ArithExpr a, int b) { return a >= MkNum(a, b); } + public static BoolExpr operator >=(ArithExpr a, int b) + { + using var rhs = MkNum(a, b); + return a >= rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator >=(ArithExpr a, double b) { return a >= MkNum(a, b); } + public static BoolExpr operator >=(ArithExpr a, double b) + { + using var rhs = MkNum(a, b); + return a >= rhs; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator >=(int a, ArithExpr b) { return MkNum(b, a) >= b; } + public static BoolExpr operator >=(int a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs >= b; + } /// Operator overloading for arithmetical operator - public static BoolExpr operator >=(double a, ArithExpr b) { return MkNum(b, a) >= b; } + public static BoolExpr operator >=(double a, ArithExpr b) + { + using var lhs = MkNum(b, a); + return lhs >= b; + } #endregion } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 342723663..b4a88add2 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -18,10 +18,10 @@ Notes: --*/ using System; -using System.Diagnostics; using System.Collections.Generic; -using System.Runtime.InteropServices; +using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; namespace Microsoft.Z3 { @@ -202,7 +202,7 @@ namespace Microsoft.Z3 /// public UninterpretedSort MkUninterpretedSort(string str) { - using var sym = MkSymbol(str); + using var sym = MkSymbol(str); return MkUninterpretedSort(sym); } @@ -312,9 +312,18 @@ namespace Microsoft.Z3 public EnumSort MkEnumSort(string name, params string[] enumNames) { Debug.Assert(enumNames != null); - using var sname = MkSymbol(name); - using var snames = MkSymbols(enumNames); - return new EnumSort(this, sname, snames); + + var enumSymbols = MkSymbols(enumNames); + try + { + using var symbol = MkSymbol(name); + return new EnumSort(this, symbol, enumSymbols); + } + finally + { + foreach (var enumSymbol in enumSymbols) + enumSymbol.Dispose(); + } } /// @@ -338,8 +347,8 @@ namespace Microsoft.Z3 Debug.Assert(elemSort != null); CheckContextMatch(elemSort); - using var sname = MkSymbol(name); - return new ListSort(this, sname, elemSort); + using var symbol = MkSymbol(name); + return new ListSort(this, symbol, elemSort); } /// @@ -366,8 +375,8 @@ namespace Microsoft.Z3 /// The size of the sort public FiniteDomainSort MkFiniteDomainSort(string name, ulong size) { - using var sname = MkSymbol(name); - return new FiniteDomainSort(this, sname, size); + using var symbol = MkSymbol(name); + return new FiniteDomainSort(this, symbol, size); } @@ -401,10 +410,19 @@ namespace Microsoft.Z3 /// public Constructor MkConstructor(string name, string recognizer, string[] fieldNames = null, Sort[] sorts = null, uint[] sortRefs = null) { - using var sname = MkSymbol(name); - using var srecognizer = MkSymbol(recognizer); - using var sfieldNames = MkSymbols(fieldNames); - return new Constructor(this, sname, srecognizer, sfieldNames, sorts, sortRefs); + + using var nameSymbol = MkSymbol(name); + using var recognizerSymbol = MkSymbol(recognizer); + var fieldSymbols = MkSymbols(fieldNames); + try + { + return new Constructor(this, nameSymbol, recognizerSymbol, fieldSymbols, sorts, sortRefs); + } + finally + { + foreach (var fieldSymbol in fieldSymbols) + fieldSymbol.Dispose(); + } } /// @@ -431,8 +449,8 @@ namespace Microsoft.Z3 Debug.Assert(constructors.All(c => c != null)); CheckContextMatch(constructors); - using var sname = MkSymbol(name); - return new DatatypeSort(this, sname, constructors); + using var symbol = MkSymbol(name); + return new DatatypeSort(this, symbol, constructors); } /// @@ -480,8 +498,17 @@ namespace Microsoft.Z3 Debug.Assert(names.Length == c.Length); //Debug.Assert(Contract.ForAll(0, c.Length, j => c[j] != null)); //Debug.Assert(names.All(name => name != null)); - var snames = MkSymbols(names); - return MkDatatypeSorts(snames, c); + + var symbols = MkSymbols(names); + try + { + return MkDatatypeSorts(symbols, c); + } + finally + { + foreach (var symbol in symbols) + symbol.Dispose(); + } } /// @@ -542,8 +569,8 @@ namespace Microsoft.Z3 CheckContextMatch(domain); CheckContextMatch(range); - using var sname = MkSymbol(name); - return new FuncDecl(this, sname, domain, range); + using var symbol = MkSymbol(name); + return new FuncDecl(this, symbol, domain, range); } /// @@ -556,8 +583,8 @@ namespace Microsoft.Z3 CheckContextMatch(domain); CheckContextMatch(range); - using var sname = MkSymbol(name); - return new FuncDecl(this, sname, domain, range, true); + using var symbol = MkSymbol(name); + return new FuncDecl(this, symbol, domain, range, true); } /// @@ -585,9 +612,9 @@ namespace Microsoft.Z3 CheckContextMatch(domain); CheckContextMatch(range); - using var sname = MkSymbol(name); + using var symbol = MkSymbol(name); Sort[] q = new Sort[] { domain }; - return new FuncDecl(this, sname, q, range); + return new FuncDecl(this, symbol, q, range); } /// @@ -626,8 +653,8 @@ namespace Microsoft.Z3 Debug.Assert(range != null); CheckContextMatch(range); - using var sname = MkSymbol(name); - return new FuncDecl(this, sname, null, range); + using var symbol = MkSymbol(name); + return new FuncDecl(this, symbol, null, range); } /// @@ -694,8 +721,9 @@ namespace Microsoft.Z3 public Expr MkConst(string name, Sort range) { Debug.Assert(range != null); - using var sname = MkSymbol(name); - return MkConst(sname, range); + + using var symbol = MkSymbol(name); + return MkConst(symbol, range); } /// @@ -736,8 +764,8 @@ namespace Microsoft.Z3 /// public BoolExpr MkBoolConst(string name) { - using var sname = MkSymbol(name); - return (BoolExpr)MkConst(sname, BoolSort); + using var symbol = MkSymbol(name); + return (BoolExpr)MkConst(symbol, BoolSort); } /// @@ -785,8 +813,9 @@ namespace Microsoft.Z3 public BitVecExpr MkBVConst(Symbol name, uint size) { Debug.Assert(name != null); - using var sort = MkBitVecSort(size); - return (BitVecExpr)MkConst(name, sort); + + using var sort = MkBitVecSort(size); + return (BitVecExpr)MkConst(name, sort); } /// @@ -794,7 +823,7 @@ namespace Microsoft.Z3 /// public BitVecExpr MkBVConst(string name, uint size) { - using var sort = MkBitVecSort(size); + using var sort = MkBitVecSort(size); return (BitVecExpr)MkConst(name, sort); } #endregion @@ -956,17 +985,15 @@ namespace Microsoft.Z3 Debug.Assert(ts != null); Debug.Assert(ts.All(a => a != null)); CheckContextMatch(ts); - BoolExpr r = null; - foreach (var t in ts) - { - if (r == null) - r = t; - else - r = MkXor(r, t); - } - if (r == null) - r = MkTrue(); - return r; + + return ts.Any() + ? ts + .Aggregate(MkFalse(), (r, t) => + { + using (r) + return MkXor(r, t); + }) + : MkTrue(); } /// @@ -2041,7 +2068,8 @@ namespace Microsoft.Z3 Debug.Assert(domain != null); Debug.Assert(range != null); - return (ArrayExpr)MkConst(name, MkArraySort(domain, range)); + using var sort = MkArraySort(domain, range); + return (ArrayExpr)MkConst(name, sort); } /// @@ -2051,9 +2079,10 @@ namespace Microsoft.Z3 { Debug.Assert(domain != null); Debug.Assert(range != null); - using var sort = MkArraySort(domain, range); - using var sname = MkSymbol(name); - return (ArrayExpr)MkConst(sname, sort); + + using var symbol = MkSymbol(name); + using var sort = MkArraySort(domain, range); + return (ArrayExpr)MkConst(symbol, sort); } @@ -3051,8 +3080,8 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(string v, uint size) { - - return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); + using var sort = MkBitVecSort(size); + return (BitVecNum)MkNumeral(v, sort); } /// @@ -3062,8 +3091,8 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(int v, uint size) { - - return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); + using var sort = MkBitVecSort(size); + return (BitVecNum)MkNumeral(v, sort); } /// @@ -3073,8 +3102,8 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(uint v, uint size) { - - return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); + using var sort = MkBitVecSort(size); + return (BitVecNum)MkNumeral(v, sort); } /// @@ -3084,8 +3113,8 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(long v, uint size) { - - return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); + using var sort = MkBitVecSort(size); + return (BitVecNum)MkNumeral(v, sort); } /// @@ -3095,8 +3124,8 @@ namespace Microsoft.Z3 /// the size of the bit-vector public BitVecNum MkBV(ulong v, uint size) { - - return (BitVecNum)MkNumeral(v, MkBitVecSort(size)); + using var sort = MkBitVecSort(size); + return (BitVecNum)MkNumeral(v, sort); } /// @@ -3343,7 +3372,7 @@ namespace Microsoft.Z3 uint cd = AST.ArrayLength(decls); if (csn != cs || cdn != cd) throw new Z3Exception("Argument size mismatch"); - ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_string(nCtx, str, + using ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_string(nCtx, str, AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls))); return assertions.ToBoolExprArray(); @@ -3362,7 +3391,7 @@ namespace Microsoft.Z3 uint cd = AST.ArrayLength(decls); if (csn != cs || cdn != cd) throw new Z3Exception("Argument size mismatch"); - ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_file(nCtx, fileName, + using ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_file(nCtx, fileName, AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls))); return assertions.ToBoolExprArray(); @@ -3847,8 +3876,8 @@ namespace Microsoft.Z3 /// public Solver MkSolver(string logic) { - using var slogic = MkSymbol(logic); - return MkSolver(slogic); + using var symbol = MkSymbol(logic); + return MkSolver(symbol); } /// @@ -4937,16 +4966,16 @@ namespace Microsoft.Z3 Fixedpoint_DRQ.Clear(this); Optimize_DRQ.Clear(this); - if (m_boolSort != null) m_boolSort.Dispose(); - if (m_intSort != null) m_intSort.Dispose(); - if (m_realSort != null) m_realSort.Dispose(); - if (m_stringSort != null) m_stringSort.Dispose(); - if (m_charSort != null) m_charSort.Dispose(); + if (m_boolSort != null) m_boolSort.Dispose(); + if (m_intSort != null) m_intSort.Dispose(); + if (m_realSort != null) m_realSort.Dispose(); + if (m_stringSort != null) m_stringSort.Dispose(); + if (m_charSort != null) m_charSort.Dispose(); m_boolSort = null; m_intSort = null; m_realSort = null; m_stringSort = null; - m_charSort = null; + m_charSort = null; if (refCount == 0 && m_ctx != IntPtr.Zero) { m_n_err_handler = null; diff --git a/src/api/dotnet/DatatypeSort.cs b/src/api/dotnet/DatatypeSort.cs index 943d3753f..5ad66bfa4 100644 --- a/src/api/dotnet/DatatypeSort.cs +++ b/src/api/dotnet/DatatypeSort.cs @@ -79,7 +79,7 @@ namespace Microsoft.Z3 FuncDecl[][] res = new FuncDecl[n][]; for (uint i = 0; i < n; i++) { - FuncDecl fd = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i)); + using FuncDecl fd = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i)); uint ds = fd.DomainSize; FuncDecl[] tmp = new FuncDecl[ds]; for (uint j = 0; j < ds; j++) diff --git a/src/api/dotnet/EnumSort.cs b/src/api/dotnet/EnumSort.cs index 08c85361e..8abef3154 100644 --- a/src/api/dotnet/EnumSort.cs +++ b/src/api/dotnet/EnumSort.cs @@ -74,7 +74,8 @@ namespace Microsoft.Z3 /// public Expr Const(uint inx) { - return Context.MkApp(ConstDecl(inx)); + using var decl = ConstDecl(inx); + return Context.MkApp(decl); } /// diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index dc4de8925..15560d829 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -255,7 +255,7 @@ namespace Microsoft.Z3 get { - ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject)); + using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject)); return av.ToBoolExprArray(); } } @@ -268,7 +268,7 @@ namespace Microsoft.Z3 get { - ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject)); + using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject)); return av.ToBoolExprArray(); } } @@ -292,7 +292,7 @@ namespace Microsoft.Z3 /// public BoolExpr[] ParseFile(string file) { - ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file)); + using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file)); return av.ToBoolExprArray(); } @@ -301,7 +301,7 @@ namespace Microsoft.Z3 /// public BoolExpr[] ParseString(string s) { - ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s)); + using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s)); return av.ToBoolExprArray(); } diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index c31f649f7..c096c0755 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -203,8 +203,8 @@ namespace Microsoft.Z3 /// Essentially invokes the `simplify' tactic on the goal. public Goal Simplify(Params p = null) { - Tactic t = Context.MkTactic("simplify"); - ApplyResult res = t.Apply(this, p); + using Tactic t = Context.MkTactic("simplify"); + using ApplyResult res = t.Apply(this, p); if (res.NumSubgoals == 0) throw new Z3Exception("No subgoals"); diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index 157334242..85ab98b38 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -32,6 +32,8 @@ Microsoft Microsoft + + 8.0 diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index 0238ff974..c35c0a727 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -87,7 +87,8 @@ namespace Microsoft.Z3 if (Native.Z3_is_as_array(Context.nCtx, n) == 0) throw new Z3Exception("Argument was not an array constant"); IntPtr fd = Native.Z3_get_as_array_func_decl(Context.nCtx, n); - return FuncInterp(new FuncDecl(Context, fd)); + using var decl = new FuncDecl(Context, fd); + return FuncInterp(decl); } } else @@ -241,7 +242,7 @@ namespace Microsoft.Z3 /// Evaluate expression to a double, assuming it is a numeral already. /// public double Double(Expr t) { - var r = Eval(t, true); + using var r = Eval(t, true); return Native.Z3_get_numeral_double(Context.nCtx, r.NativeObject); } @@ -283,7 +284,7 @@ namespace Microsoft.Z3 { Debug.Assert(s != null); - ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject)); + using ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject)); return av.ToExprArray(); } diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 66b0df82c..ecd5e8e82 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -212,7 +212,7 @@ namespace Microsoft.Z3 public Handle AssertSoft(BoolExpr constraint, uint weight, string group) { Context.CheckContextMatch(constraint); - Symbol s = Context.MkSymbol(group); + using Symbol s = Context.MkSymbol(group); return new Handle(this, Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject)); } @@ -289,7 +289,7 @@ namespace Microsoft.Z3 get { - ASTVector core = new ASTVector(Context, Native.Z3_optimize_get_unsat_core(Context.nCtx, NativeObject)); + using ASTVector core = new ASTVector(Context, Native.Z3_optimize_get_unsat_core(Context.nCtx, NativeObject)); return core.ToBoolExprArray(); } } @@ -337,7 +337,7 @@ namespace Microsoft.Z3 /// private Expr[] GetLowerAsVector(uint index) { - ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index)); + using ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index)); return v.ToExprArray(); } @@ -347,7 +347,7 @@ namespace Microsoft.Z3 /// private Expr[] GetUpperAsVector(uint index) { - ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index)); + using ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index)); return v.ToExprArray(); } @@ -396,7 +396,7 @@ namespace Microsoft.Z3 get { - ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject)); + using ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject)); return assertions.ToBoolExprArray(); } } @@ -409,7 +409,7 @@ namespace Microsoft.Z3 get { - ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject)); + using ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject)); return objectives.ToExprArray(); } } diff --git a/src/api/dotnet/RatNum.cs b/src/api/dotnet/RatNum.cs index 1d485a347..a1326d7a8 100644 --- a/src/api/dotnet/RatNum.cs +++ b/src/api/dotnet/RatNum.cs @@ -62,7 +62,7 @@ namespace Microsoft.Z3 { get { - IntNum n = Numerator; + using IntNum n = Numerator; return BigInteger.Parse(n.ToString()); } } @@ -74,7 +74,7 @@ namespace Microsoft.Z3 { get { - IntNum n = Denominator; + using IntNum n = Denominator; return BigInteger.Parse(n.ToString()); } } diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index ec53b14de..52f2ad993 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -58,43 +58,92 @@ namespace Microsoft.Z3 /// /// Sets parameter on the solver /// - public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(string name, bool value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(string name, uint value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(string name, double value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(string name, string value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(string name, Symbol value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(Symbol name, bool value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(Symbol name, uint value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(Symbol name, double value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(Symbol name, string value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } + /// /// Sets parameter on the solver /// - public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + public void Set(Symbol name, Symbol value) + { + using var parameters = Context.MkParams().Add(name, value); + Parameters = parameters; + } @@ -245,7 +294,7 @@ namespace Microsoft.Z3 { get { - ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); + using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); return assertions.Size; } } @@ -258,7 +307,7 @@ namespace Microsoft.Z3 get { - ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); + using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); return assertions.ToBoolExprArray(); } } @@ -271,7 +320,7 @@ namespace Microsoft.Z3 get { - ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject)); + using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject)); return assertions.ToBoolExprArray(); } } @@ -330,9 +379,9 @@ namespace Microsoft.Z3 /// public Status Consequences(IEnumerable assumptions, IEnumerable variables, out BoolExpr[] consequences) { - ASTVector result = new ASTVector(Context); - ASTVector asms = new ASTVector(Context); - ASTVector vars = new ASTVector(Context); + using ASTVector result = new ASTVector(Context); + using ASTVector asms = new ASTVector(Context); + using ASTVector vars = new ASTVector(Context); foreach (var asm in assumptions) asms.Push(asm); foreach (var v in variables) vars.Push(v); Z3_lbool r = (Z3_lbool)Native.Z3_solver_get_consequences(Context.nCtx, NativeObject, asms.NativeObject, vars.NativeObject, result.NativeObject); @@ -391,7 +440,7 @@ namespace Microsoft.Z3 get { - ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); + using ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); return core.ToBoolExprArray(); } } @@ -424,14 +473,14 @@ namespace Microsoft.Z3 /// public IEnumerable Cube() { - ASTVector cv = new ASTVector(Context); + using ASTVector cv = new ASTVector(Context); if (CubeVariables != null) foreach (var b in CubeVariables) cv.Push(b); while (true) { var lvl = BacktrackLevel; BacktrackLevel = uint.MaxValue; - ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl)); + using ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl)); var v = r.ToBoolExprArray(); CubeVariables = cv.ToBoolExprArray(); if (v.Length == 1 && v[0].IsFalse) { From 1fa373d6c272223eab35c1a530936a39870a6989 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Mar 2022 08:21:22 -0700 Subject: [PATCH 129/258] old bug: unit of xor is false Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index b4a88add2..c8698277c 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -993,7 +993,7 @@ namespace Microsoft.Z3 using (r) return MkXor(r, t); }) - : MkTrue(); + : MkFalse(); } /// From 41d1c340675961d6415362485594c0516a3af7b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Mar 2022 12:33:15 -0700 Subject: [PATCH 130/258] remove else case Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index c8698277c..a0676b4e2 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -986,14 +986,11 @@ namespace Microsoft.Z3 Debug.Assert(ts.All(a => a != null)); CheckContextMatch(ts); - return ts.Any() - ? ts - .Aggregate(MkFalse(), (r, t) => + return ts.Aggregate(MkFalse(), (r, t) => { using (r) return MkXor(r, t); - }) - : MkFalse(); + }); } /// From 6010d751eda9a03dccf85a4490377f91a99b0ed8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Mar 2022 16:21:47 -0700 Subject: [PATCH 131/258] fix #5903 Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_rule_inliner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index d3ad54bd9..8535bf1e9 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -437,6 +437,8 @@ namespace datalog { tgt.add_rule(r); continue; } + + TRACE("dl", tout << pt_len modified = true; func_decl * pred = r->get_decl(i); @@ -449,7 +451,7 @@ namespace datalog { } } if (modified) { - datalog::del_rule(m_mc, *r0, l_true); + datalog::del_rule(m_mc, *r0, l_undef); } return modified; From 29e288367eaeebd332686abdbc675cca2ac3fc58 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Mar 2022 16:22:48 -0700 Subject: [PATCH 132/258] pre-release pipeline Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release.yml b/scripts/release.yml index 8e69be9b0..d131fb383 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -314,7 +314,7 @@ stages: jobs: - job: GitHubPublish - condition: eq(1,1) + condition: eq(0,1) displayName: "Publish to GitHub" pool: vmImage: "windows-latest" @@ -392,7 +392,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,1) + condition: eq(0,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From 669a1d63daaafdf0d3f0b76f5fe09e593d25b536 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Mar 2022 16:36:16 -0700 Subject: [PATCH 133/258] na Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_rule_inliner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 8535bf1e9..99fa1d68c 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -438,7 +438,6 @@ namespace datalog { continue; } - TRACE("dl", tout << pt_len modified = true; func_decl * pred = r->get_decl(i); From 39df8ee372e23abfc765fa4c4b7451af760821d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Mar 2022 17:39:58 -0700 Subject: [PATCH 134/258] update win build Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index bd96889a3..1b0bb111a 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -18,7 +18,7 @@ jobs: displayName: Build inputs: script: - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} && + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} && python scripts\mk_win_dist.py --${{parameters.BuildArchitecture}}-only --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk From 81a5e56c8960c3493cf63e721e192c9482d06766 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Mar 2022 18:58:27 -0700 Subject: [PATCH 135/258] publish to github Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index d131fb383..562fc8a57 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -314,7 +314,7 @@ stages: jobs: - job: GitHubPublish - condition: eq(0,1) + condition: eq(1,1) displayName: "Publish to GitHub" pool: vmImage: "windows-latest" From a9d70267242bf0e8200f221555a8b89d6b8bfd20 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Mar 2022 19:13:35 -0700 Subject: [PATCH 136/258] add note about transform Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_rule_inliner.cpp | 29 ++++++++++------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 99fa1d68c..518a63a0a 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -44,6 +44,11 @@ Subsumption transformation (remove rule): P(x) := P(x) or (exists y . Q(y) & phi(x,y)) +For plan_inlining: + TODO: order of rule inlining would affect model converter? + so shouldn't model converter process inlined rules in a specific (topopologial) order? + + --*/ @@ -377,18 +382,15 @@ namespace datalog { return something_forbidden; } - void mk_rule_inliner::plan_inlining(rule_set const & orig) - { + void mk_rule_inliner::plan_inlining(rule_set const & orig) { count_pred_occurrences(orig); scoped_ptr candidate_inlined_set = create_allowed_rule_set(orig); - while (forbid_preds_from_cycles(*candidate_inlined_set)) { + while (forbid_preds_from_cycles(*candidate_inlined_set)) candidate_inlined_set = create_allowed_rule_set(orig); - } - if (forbid_multiple_multipliers(orig, *candidate_inlined_set)) { + if (forbid_multiple_multipliers(orig, *candidate_inlined_set)) candidate_inlined_set = create_allowed_rule_set(orig); - } TRACE("dl", tout<<"rules to be inlined:\n" << (*candidate_inlined_set); ); @@ -402,16 +404,13 @@ namespace datalog { for (rule_stratifier::item_set * stratum : comps) { SASSERT(stratum->size() == 1); func_decl * pred = *stratum->begin(); - for (rule * r : candidate_inlined_set->get_predicate_rules(pred)) { + for (rule * r : candidate_inlined_set->get_predicate_rules(pred)) transform_rule(orig, r, m_inlined_rules); - } } - TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; ); + for (rule * r : m_inlined_rules) + datalog::del_rule(m_mc, *r, l_undef); - for (rule * r : m_inlined_rules) { - datalog::del_rule(m_mc, *r, l_undef); - } } bool mk_rule_inliner::transform_rule(rule_set const& orig, rule * r0, rule_set& tgt) { @@ -444,14 +443,12 @@ namespace datalog { const rule_vector& pred_rules = m_inlined_rules.get_predicate_rules(pred); for (rule * inl_rule : pred_rules) { rule_ref inl_result(m_rm); - if (try_to_inline_rule(*r.get(), *inl_rule, i, inl_result)) { + if (try_to_inline_rule(*r.get(), *inl_rule, i, inl_result)) todo.push_back(inl_result); - } } } - if (modified) { + if (modified) datalog::del_rule(m_mc, *r0, l_undef); - } return modified; } From 6d836e7e2f05a7e1a53bbc446735a49c625eb4a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 09:23:01 -0700 Subject: [PATCH 137/258] expose model update --- src/math/lp/lar_solver.h | 5 ++++- src/sat/sat_solver.cpp | 8 +++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 1cd776cc2..0c61bdcb2 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -223,7 +223,7 @@ class lar_solver : public column_namer { void insert_row_with_changed_bounds(unsigned rid); void detect_rows_with_changed_bounds_for_column(unsigned j); void detect_rows_with_changed_bounds(); - void set_value_for_nbasic_column(unsigned j, const impq & new_val); + void update_x_and_inf_costs_for_columns_with_changed_bounds(); void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); void solve_with_core_solver(); @@ -355,6 +355,9 @@ public: bp.consume(a, witness); } } + + void set_value_for_nbasic_column(unsigned j, const impq& new_val); + // lp_assert(implied_bound_is_correctly_explained(ib, explanation)); } constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side); void activate_check_on_equal(constraint_index, var_index&); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4d4c2d132..5505cfa70 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2967,11 +2967,9 @@ namespace sat { } break; case PS_SAT_CACHING: - if (m_search_state == s_sat) { - for (unsigned i = 0; i < m_phase.size(); ++i) { - m_phase[i] = m_best_phase[i]; - } - } + if (m_search_state == s_sat) + for (unsigned i = 0; i < m_phase.size(); ++i) + m_phase[i] = m_best_phase[i]; break; case PS_RANDOM: for (auto& p : m_phase) p = (m_rand() % 2) == 0; From 86af723db7ecf47fd17e83f5de1110bbb13f284f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 09:40:29 -0700 Subject: [PATCH 138/258] remove left-over debug output Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 1a2def0c8..b00a33ad7 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -3983,7 +3983,6 @@ namespace z3 { scoped_cb _cb(p, cb); expr value(p->ctx(), _value); expr var(p->ctx(), _var); - std::cout << "Fixed " << cb << "\n"; p->m_fixed_eh(var, value); } @@ -4151,7 +4150,6 @@ namespace z3 { assert(cb); expr conseq = ctx().bool_val(false); array _fixed(fixed); - std::cout << "conflict " << cb << " " << fixed << "\n"; Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq); } From eaa2fb76cada93ccddc5a619393f0d5a469b2f06 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 11:46:27 -0700 Subject: [PATCH 139/258] update release pipeline with x86 Nuget Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 134 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 117 insertions(+), 17 deletions(-) diff --git a/scripts/release.yml b/scripts/release.yml index 562fc8a57..579b9c2a5 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -155,8 +155,8 @@ stages: - stage: Package jobs: - - job: NuGetPackage - displayName: "NuGet packaging" + - job: NuGet64 + displayName: "NuGet 64 packaging" pool: vmImage: "windows-latest" steps: @@ -169,23 +169,22 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Win64 Build' inputs: - artifact: 'WindowsBuild-x64' - path: $(Agent.TempDirectory)\package - - task: DownloadPipelineArtifact@2 - displayName: 'Download Win32 Build' - inputs: - artifact: 'WindowsBuild-x86' + artifact: 'Windows64' path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu Build' inputs: - artifact: 'UbuntuBuild' + artifact: 'Ubuntu' path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download macOS Build' inputs: - artifact: 'macOSBuild' + artifact: 'Mac' path: $(Agent.TempDirectory)\package + - task: NuGetToolInstaller@0 + inputs: + versionSpec: 5.x + checkLatest: false - task: PythonScript@0 displayName: 'Python: assemble files' inputs: @@ -200,10 +199,6 @@ stages: $(Build.SourceVersion) $(Build.SourcesDirectory) symbols - - task: NuGetToolInstaller@0 - inputs: - versionSpec: 5.x - checkLatest: false - task: NugetCommand@2 displayName: 'NuGet Pack Symbols' inputs: @@ -266,7 +261,107 @@ stages: - task: PublishPipelineArtifact@1 inputs: targetPath: $(Build.ArtifactStagingDirectory) - artifactName: 'NuGetPackage' + artifactName: 'NuGet' + + - job: NuGet32 + displayName: "NuGet 32 packaging" + pool: + vmImage: "windows-latest" + steps: + - powershell: write-host $(System.DefinitionId) + displayName: 'System.DefinitionId' + - powershell: write-host $(Build.BuildId) + displayName: 'Build.BuildId' + - powershell: write-host $(System.TeamProjectId) + displayName: 'System.TeamProjectId' + - task: DownloadPipelineArtifact@2 + displayName: 'Download Win32 Build' + inputs: + artifact: 'Windows32' + path: $(Agent.TempDirectory)\package + - task: NuGetToolInstaller@0 + inputs: + versionSpec: 5.x + checkLatest: false + - task: PythonScript@0 + displayName: 'Python: assemble files' + inputs: + scriptSource: 'filepath' + scriptPath: scripts\mk_nuget_task.py + workingDirectory: $(Agent.TempDirectory)\package + arguments: + $(Agent.TempDirectory)\package + $(ReleaseVersion) + $(Build.Repository.Uri) + $(Build.SourceBranchName) + $(Build.SourceVersion) + $(Build.SourcesDirectory) + symbols + x86 + - task: NugetCommand@2 + displayName: 'NuGet Pack Symbols' + inputs: + command: custom + arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' + - task: EsrpCodeSigning@1 + displayName: 'Sign Package' + inputs: + ConnectedServiceName: 'z3-esrp-signing-2' + FolderPath: $(Build.ArtifactStagingDirectory) + Pattern: Microsoft.Z3.x86.$(ReleaseVersion).nupkg + signConfigType: 'inlineSignParams' + inlineOperation: | + [ + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetSign", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + SessionTimeout: '60' + MaxConcurrency: '50' + MaxRetryAttempts: '5' + - task: EsrpCodeSigning@1 + displayName: 'Sign Symbol Package' + inputs: + ConnectedServiceName: 'z3-esrp-signing-2' + FolderPath: $(Build.ArtifactStagingDirectory) + Pattern: Microsoft.Z3.x86.$(ReleaseVersion).snupkg + signConfigType: 'inlineSignParams' + inlineOperation: | + [ + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetSign", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + SessionTimeout: '60' + MaxConcurrency: '50' + MaxRetryAttempts: '5' + - task: PublishPipelineArtifact@1 + inputs: + targetPath: $(Build.ArtifactStagingDirectory) + artifactName: 'NuGet32' + - job: PythonPackage displayName: "Python packaging" @@ -350,9 +445,14 @@ stages: artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 - displayName: 'Download NuGet Package' + displayName: 'Download NuGet64 Package' inputs: - artifact: 'NuGetPackage' + artifact: 'NuGet' + path: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: 'Download NuGet32 Package' + inputs: + artifact: 'NuGet32' path: $(Agent.TempDirectory) - task: GitHubRelease@0 inputs: From fd1f5cdd0f455d60c4c9ed86bd702ca14560e3e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 12:24:46 -0700 Subject: [PATCH 140/258] fix callback type declarations for propagators --- scripts/update_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 2daf0a7a7..ab1b4d6fd 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1824,9 +1824,9 @@ push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p) pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint) fresh_eh_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) -fixed_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint, ctypes.c_void_p) +fixed_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) final_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) -eq_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint, ctypes.c_uint) +eq_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) _lib.Z3_solver_propagate_init.restype = None _lib.Z3_solver_propagate_init.argtypes = [ContextObj, SolverObj, ctypes.c_void_p, push_eh_type, pop_eh_type, fresh_eh_type] From cfe02edda5721e4a1b9e97ce0d2b8404a9577e90 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 12:26:48 -0700 Subject: [PATCH 141/258] remove stale return --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index cd4aee24f..b58ac28be 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11378,7 +11378,7 @@ class UserPropagateBase: def add(self, e): assert self.solver assert not self._ctx - return Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast) + Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast) # # Propagation can only be invoked as during a fixed or final callback. From 964e513353934e76ccd0831827ca3aad29840d85 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 12:37:01 -0700 Subject: [PATCH 142/258] re-add bv_eq_axioms, fix #5842 --- src/smt/params/smt_params_helper.pyg | 1 + src/smt/params/theory_bv_params.cpp | 2 ++ src/smt/theory_bv.cpp | 46 ++++++++++++++++------------ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 0eb4cbe9f..e78fe8fa9 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -49,6 +49,7 @@ def_module_params(module_name='smt', ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), ('bv.watch_diseq', BOOL, False, 'use watch lists instead of eager axioms for bit-vectors'), ('bv.delay', BOOL, True, 'delay internalize expensive bit-vector operations'), + ('bv.eq_axioms', BOOL, True, 'enable redundant equality axioms for bit-vectors'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), ('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation, relevant only if smt.arith.solver=2'), diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index 968bf3abb..61b4d967a 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -27,6 +27,7 @@ void theory_bv_params::updt_params(params_ref const & _p) { m_bv_reflect = p.bv_reflect(); m_bv_enable_int2bv2int = p.bv_enable_int2bv(); m_bv_delay = p.bv_delay(); + m_bv_eq_axioms = p.bv_eq_axioms(); } #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; @@ -36,6 +37,7 @@ void theory_bv_params::display(std::ostream & out) const { DISPLAY_PARAM(m_hi_div0); DISPLAY_PARAM(m_bv_reflect); DISPLAY_PARAM(m_bv_lazy_le); + DISPLAY_PARAM(m_bv_eq_axioms); DISPLAY_PARAM(m_bv_cc); DISPLAY_PARAM(m_bv_blast_max_size); DISPLAY_PARAM(m_bv_enable_int2bv2int); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 6c6904c39..341daedec 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -430,6 +430,8 @@ namespace smt { }; void theory_bv::add_fixed_eq(theory_var v1, theory_var v2) { + if (!params().m_bv_eq_axioms) + return; if (v1 > v2) { std::swap(v1, v2); @@ -1150,6 +1152,8 @@ namespace smt { } void theory_bv::expand_diseq(theory_var v1, theory_var v2) { + if (!params().m_bv_eq_axioms) + return; SASSERT(get_bv_size(v1) == get_bv_size(v2)); if (v1 > v2) { @@ -1316,27 +1320,29 @@ namespace smt { } else { ctx.assign(consequent, mk_bit_eq_justification(v1, v2, consequent, antecedent)); + if (params().m_bv_eq_axioms) { - literal_vector lits; - lits.push_back(~consequent); - lits.push_back(antecedent); - literal eq = mk_eq(get_expr(v1), get_expr(v2), false); - lits.push_back(~eq); - // - // Issue #3035: - // merge_eh invokes assign_bit, which updates the propagation queue and includes the - // theory axiom for the propagated equality. When relevancy is non-zero, propagation may get - // lost on backtracking because the propagation queue is reset on conflicts. - // An alternative approach is to ensure the propagation queue is chronological with - // backtracking scopes (ie., it doesn't get reset, but shrunk to a previous level, and similar - // with a qhead indicator. - // - ctx.mark_as_relevant(lits[0]); - ctx.mark_as_relevant(lits[1]); - ctx.mark_as_relevant(lits[2]); - { - scoped_trace_stream _sts(*this, lits); - ctx.mk_th_axiom(get_id(), lits.size(), lits.data()); + literal_vector lits; + lits.push_back(~consequent); + lits.push_back(antecedent); + literal eq = mk_eq(get_expr(v1), get_expr(v2), false); + lits.push_back(~eq); + // + // Issue #3035: + // merge_eh invokes assign_bit, which updates the propagation queue and includes the + // theory axiom for the propagated equality. When relevancy is non-zero, propagation may get + // lost on backtracking because the propagation queue is reset on conflicts. + // An alternative approach is to ensure the propagation queue is chronological with + // backtracking scopes (ie., it doesn't get reset, but shrunk to a previous level, and similar + // with a qhead indicator. + // + ctx.mark_as_relevant(lits[0]); + ctx.mark_as_relevant(lits[1]); + ctx.mark_as_relevant(lits[2]); + { + scoped_trace_stream _sts(*this, lits); + ctx.mk_th_axiom(get_id(), lits.size(), lits.data()); + } } if (m_wpos[v2] == idx) From dfa65443e9a8ee0e16f9403b9c16fc64234b2d3a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 13:51:58 -0700 Subject: [PATCH 143/258] fix name for artifact Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 4 ++-- src/smt/params/smt_params_helper.pyg | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/release.yml b/scripts/release.yml index 579b9c2a5..53f0b95dd 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -169,7 +169,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Win64 Build' inputs: - artifact: 'Windows64' + artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu Build' @@ -277,7 +277,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Win32 Build' inputs: - artifact: 'Windows32' + artifact: 'WindowsBuild-x86' path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index e78fe8fa9..33b3e458f 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -53,7 +53,7 @@ def_module_params(module_name='smt', ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), ('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation, relevant only if smt.arith.solver=2'), - ('arith.nl.nra', BOOL, True, 'call nra_solver when incremental lianirization does not produce a lemma, this option is ignored when arith.nl=false, relevant only if smt.arith.solver=6'), + ('arith.nl.nra', BOOL, True, 'call nra_solver when incremental linearization does not produce a lemma, this option is ignored when arith.nl=false, relevant only if smt.arith.solver=6'), ('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters, relevant only if smt.arith.solver=2'), ('arith.nl.rounds', UINT, 1024, 'threshold for number of (nested) final checks for non linear arithmetic, relevant only if smt.arith.solver=2'), ('arith.nl.order', BOOL, True, 'run order lemmas'), From b5b9c85c404bc26228f8a92e8ddd6bbfb075afc8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 15:24:53 -0700 Subject: [PATCH 144/258] call it UbuntuBuild --- scripts/release.yml | 2 +- src/api/python/z3/z3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release.yml b/scripts/release.yml index 53f0b95dd..31c6f8226 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -174,7 +174,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu Build' inputs: - artifact: 'Ubuntu' + artifact: 'UbuntuBuild' path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download macOS Build' diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index b58ac28be..5e177ef08 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11387,7 +11387,7 @@ class UserPropagateBase: _ids, num_fixed = _to_ast_array(ids) num_eqs = len(eqs) _lhs, _num_lhs = _to_ast_array([x for x, y in eqs]) - _rhs, _num_lhs = _to_ast_array([y for x, y in eqs]) + _rhs, _num_rhs = _to_ast_array([y for x, y in eqs]) Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p( self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast) From 9061ca58f1f75cdc362382ab564664d30a5de498 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 15:25:50 -0700 Subject: [PATCH 145/258] call it macOSBuild --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 31c6f8226..030ca0537 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -179,7 +179,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download macOS Build' inputs: - artifact: 'Mac' + artifact: 'macOSBuild' path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: From 3439d2407bacb786bdad170ecb4a3d6987cbc394 Mon Sep 17 00:00:00 2001 From: Chaoqi Zhang Date: Mon, 21 Mar 2022 02:21:11 +0800 Subject: [PATCH 146/258] Revert "doc: update readme (#5898)" (#5905) This reverts commit 313b87f3c68f849b1747e0f6eb5cf89ff8e8c9b5. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 44e643662..4849c33d8 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ python scripts/mk_make.py -x then: ```bash -mkdir build && cd build +cd build nmake ``` @@ -54,7 +54,7 @@ Execute: ```bash python scripts/mk_make.py -mkdir build && cd build +cd build make sudo make install ``` @@ -86,7 +86,7 @@ the ``--prefix=`` command line option to change the install prefix. For example: ```bash python scripts/mk_make.py --prefix=/home/leo -mkdir build && cd build +cd build make make install ``` From bbb27775edcf3b27f0275abef9f1e166efe0f3cd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Mar 2022 15:34:06 -0700 Subject: [PATCH 147/258] ensure that objects in callback are of sort Ast. --- src/api/python/z3/z3.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 5e177ef08..6f4dcf430 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11252,35 +11252,38 @@ def user_prop_fresh(id, ctx): _prop_closures.set(new_prop.id, new_prop) return ctypes.c_void_p(new_prop.id) +def to_Ast(ptr,): + ast = Ast(ptr) + super(ctypes.c_void_p, ast).__init__(ptr) + return ast def user_prop_fixed(ctx, cb, id, value): prop = _prop_closures.get(ctx) prop.cb = cb - prop.fixed(_to_expr_ref(ctypes.c_void_p(id), prop.ctx()), _to_expr_ref(ctypes.c_void_p(value), prop.ctx())) + id = _to_expr_ref(to_Ast(id), prop.ctx()) + value = _to_expr_ref(to_Ast(value), prop.ctx()) + prop.fixed(id, value) prop.cb = None - def user_prop_final(ctx, cb): prop = _prop_closures.get(ctx) prop.cb = cb prop.final() prop.cb = None - def user_prop_eq(ctx, cb, x, y): prop = _prop_closures.get(ctx) prop.cb = cb - x = _to_expr_ref(ctypes.c_void_p(x), prop.ctx()) - y = _to_expr_ref(ctypes.c_void_p(y), prop.ctx()) + x = _to_expr_ref(to_Ast(x), prop.ctx()) + y = _to_expr_ref(to_Ast(y), prop.ctx()) prop.eq(x, y) prop.cb = None - def user_prop_diseq(ctx, cb, x, y): prop = _prop_closures.get(ctx) prop.cb = cb - x = _to_expr_ref(ctypes.c_void_p(x), prop.ctx()) - y = _to_expr_ref(ctypes.c_void_p(y), prop.ctx()) + x = _to_expr_ref(to_Ast(x), prop.ctx()) + y = _to_expr_ref(to_Ast(y), prop.ctx()) prop.diseq(x, y) prop.cb = None From f053daa051ec823890212903b97c3a27ae41c5b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Mar 2022 11:24:31 -0700 Subject: [PATCH 148/258] fix #5906 Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_mk_simple_joins.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index 11e366f90..3fa52ae2f 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -370,7 +370,7 @@ namespace datalog { rule * one_parent = inf.m_rules.back(); func_decl* parent_head = one_parent->get_decl(); - const char * one_parent_name = parent_head->get_name().bare_str(); + std::string one_parent_name = parent_head->get_name().str(); std::string parent_name; if (inf.m_rules.size() > 1) { parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1); From b4873d226c0d093577b9f4181f9c6d9ed8f51cdf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Mar 2022 11:40:19 -0700 Subject: [PATCH 149/258] fix #5907 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_datatype.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 1aa8bbea3..035b647dc 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -254,6 +254,8 @@ namespace smt { app_ref n_is_con(m.mk_app(rec, own), m); ctx.internalize(n_is_con, false); literal lits[2] = { ~is_con, literal(ctx.get_bool_var(n_is_con)) }; + ctx.mark_as_relevant(lits[0]); + ctx.mark_as_relevant(lits[1]); std::function fn = [&]() { return literal_vector(2, lits); }; scoped_trace_stream _st(*this, fn); ctx.mk_th_axiom(get_id(), 2, lits); From 1e8bae01e9b314f5771a370a7a393d848d5eadbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Mar 2022 13:12:29 -0700 Subject: [PATCH 150/258] enable pypi in release pipeline Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 030ca0537..d82c9f919 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -492,7 +492,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(0,1) + condition: eq(1,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From f1806d32d6f21fd4df7a08719abbc1f6493d9dc5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Mar 2022 13:25:44 -0700 Subject: [PATCH 151/258] remove buggy code, close, fix #5825 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 02faebba5..9fcc35b2d 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -936,22 +936,13 @@ expr_ref seq_rewriter::mk_seq_last(expr* t) { } /* -* In general constructs substring(t,0,|t|-1) but if t = substring(s,0,k) then simplifies to substring(s,0,k-1) -* This method assumes that |t| > 0, thus, if t = substring(s,0,k) then k > 0 so substring(s,0,k-1) is correct. +* In general constructs substring(t,0,|t|-1) +* Incorrect comment: "but if t = substring(s,0,k) then simplifies to substring(s,0,k-1). +* This method assumes that |t| > 0, thus, if t = substring(s,0,k) then k > 0 so substring(s,0,k-1) is correct." +* No: if k > |s| then substring(s,0,k) = substring(s,0,k-1) */ expr_ref seq_rewriter::mk_seq_butlast(expr* t) { - expr_ref result(m()); - expr* s, * j, * k; - rational v; - if (false && str().is_extract(t, s, j, k) && m_autil.is_numeral(j, v) && v.is_zero()) { - expr_ref_vector k_min_1(m()); - k_min_1.push_back(k); - k_min_1.push_back(minus_one()); - result = str().mk_substr(s, j, m_autil.mk_add_simplify(k_min_1)); - } - else - result = str().mk_substr(t, zero(), m_autil.mk_sub(str().mk_length(t), one())); - return result; + return expr_ref(str().mk_substr(t, zero(), m_autil.mk_sub(str().mk_length(t), one())), m()); } /* From a418678cd43f67e98b97052bf6675e397c6edb00 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Mar 2022 14:34:34 -0700 Subject: [PATCH 152/258] increment version number --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 2 +- scripts/release.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 477410ba8..a9e121d02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.8.15.0 LANGUAGES CXX) +project(Z3 VERSION 4.8.16.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 147e310a7..a19ce613f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 8, 15, 0) + set_version(4, 8, 16, 0) # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index cccf55a31..04e0a8e04 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,5 +1,5 @@ variables: - ReleaseVersion: '4.8.15' + ReleaseVersion: '4.8.16' MacFlags: 'CXXFLAGS="-arch arm64 -arch x86_64" LINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" SLINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" FPMATH_ENABLED=False' stages: diff --git a/scripts/release.yml b/scripts/release.yml index d82c9f919..cd860d177 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.8.15' + ReleaseVersion: '4.8.16' stages: From 00608cd719d608f8cd653a8c4ea32490cc1cce3c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Mar 2022 14:38:59 -0700 Subject: [PATCH 153/258] notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 78cd70fb0..8e61f55bd 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -10,6 +10,10 @@ Version 4.8.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.8.15 +============== + - elaborate user propagator API. Change id based scheme to expressions + - includes a Web Assembly ffi API thanks to Kevin Gibbons Version 4.8.14 ============== From 20bd59bb20268ba97f9f286b7c0fbd72687f5862 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Mar 2022 10:15:00 -0700 Subject: [PATCH 154/258] #5778 - missed tracking literal assignment justification Signed-off-by: Nikolaj Bjorner --- src/ast/euf/euf_egraph.cpp | 25 +++++++++++++++++++++++-- src/ast/euf/euf_egraph.h | 10 +++------- src/ast/euf/euf_enode.h | 1 + src/sat/smt/euf_internalize.cpp | 5 +++-- src/sat/smt/euf_solver.cpp | 2 +- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 8a3a4e002..652663b70 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -293,11 +293,12 @@ namespace euf { VERIFY(n->num_args() == 0 || !n->merge_enabled() || m_table.contains(n)); } - void egraph::set_value(enode* n, lbool value) { + void egraph::set_value(enode* n, lbool value, justification j) { if (n->value() == l_undef) { force_push(); TRACE("euf", tout << bpp(n) << " := " << value << "\n";); n->set_value(value); + n->set_justification(j); m_updates.push_back(update_record(n, update_record::value_assignment())); } } @@ -657,6 +658,7 @@ namespace euf { push_lca(n1->get_arg(1), n2->get_arg(0)); return; } + TRACE("euf_verbose", tout << bpp(n1) << " " << bpp(n2) << "\n"); for (unsigned i = 0; i < n1->num_args(); ++i) push_lca(n1->get_arg(i), n2->get_arg(i)); @@ -713,6 +715,15 @@ namespace euf { explain_todo(justifications); } + template + void egraph::explain_eq(ptr_vector& justifications, enode* a, enode* b, justification const& j) { + if (j.is_external()) + justifications.push_back(j.ext()); + else if (j.is_congruence()) + push_congruence(a, b, j.is_commutative()); + } + + template void egraph::explain_eq(ptr_vector& justifications, enode* a, enode* b) { SASSERT(a->get_root() == b->get_root()); @@ -746,11 +757,21 @@ namespace euf { void egraph::explain_todo(ptr_vector& justifications) { for (unsigned i = 0; i < m_todo.size(); ++i) { enode* n = m_todo[i]; - if (n->m_target && !n->is_marked1()) { + if (n->is_marked1()) + continue; + if (n->m_target) { n->mark1(); CTRACE("euf_verbose", m_display_justification, n->m_justification.display(tout << n->get_expr_id() << " = " << n->m_target->get_expr_id() << " ", m_display_justification) << "\n";); explain_eq(justifications, n, n->m_target, n->m_justification); } + else if (!n->is_marked1() && n->value() != l_undef) { + n->mark1(); + if (m.is_true(n->get_expr()) || m.is_false(n->get_expr())) + continue; + justification j = n->m_justification; + SASSERT(j.is_external()); + justifications.push_back(j.ext()); + } } } diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index a91dbf4a4..55f94f0f2 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -226,12 +226,8 @@ namespace euf { void erase_from_table(enode* p); template - void explain_eq(ptr_vector& justifications, enode* a, enode* b, justification const& j) { - if (j.is_external()) - justifications.push_back(j.ext()); - else if (j.is_congruence()) - push_congruence(a, b, j.is_commutative()); - } + void explain_eq(ptr_vector& justifications, enode* a, enode* b, justification const& j); + template void explain_todo(ptr_vector& justifications); @@ -295,7 +291,7 @@ namespace euf { void add_th_var(enode* n, theory_var v, theory_id id); void set_th_propagates_diseqs(theory_id id); void set_merge_enabled(enode* n, bool enable_merge); - void set_value(enode* n, lbool value); + void set_value(enode* n, lbool value, justification j); void set_bool_var(enode* n, unsigned v) { n->set_bool_var(v); } void set_relevant(enode* n); void set_default_relevant(bool b) { m_default_relevant = b; } diff --git a/src/ast/euf/euf_enode.h b/src/ast/euf/euf_enode.h index 850e183e8..dc98d95c8 100644 --- a/src/ast/euf/euf_enode.h +++ b/src/ast/euf/euf_enode.h @@ -133,6 +133,7 @@ namespace euf { void del_th_var(theory_id id) { m_th_vars.del_var(id); } void set_merge_enabled(bool m) { m_merge_enabled = m; } void set_value(lbool v) { m_value = v; } + void set_justification(justification j) { m_justification = j; } void set_is_equality() { m_is_equality = true; } void set_bool_var(sat::bool_var v) { m_bool_var = v; } diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 6cc72eba5..116621dcc 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -190,8 +190,9 @@ namespace euf { m_egraph.set_bool_var(n, v); if (m.is_eq(e) || m.is_or(e) || m.is_and(e) || m.is_not(e)) m_egraph.set_merge_enabled(n, false); - if (s().value(lit) != l_undef) - m_egraph.set_value(n, s().value(lit)); + lbool val = s().value(lit); + if (val != l_undef) + m_egraph.set_value(n, val, justification::external(to_ptr(val == l_true ? lit : ~lit))); return lit; } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 3c7342136..2ef77ac6a 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -309,7 +309,7 @@ namespace euf { if (!n) return; bool sign = l.sign(); - m_egraph.set_value(n, sign ? l_false : l_true); + m_egraph.set_value(n, sign ? l_false : l_true, justification::external(to_ptr(l))); for (auto const& th : enode_th_vars(n)) m_id2solver[th.get_id()]->asserted(l); From 9011100df27d5b8f5984dd8d9b424ecf37b37c6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Mar 2022 15:25:35 -0700 Subject: [PATCH 155/258] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ac83a2775..051580bb3 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,7 @@ src/api/js/build/ src/api/js/**/*.d.ts !src/api/js/scripts/*.js !src/api/js/src/*.js +debug/* out/** *.bak From 4b1419261faee8b9b3122f95e54b5ea328529af3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Mar 2022 16:23:43 -0700 Subject: [PATCH 156/258] #5778 --- src/sat/smt/q_solver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 2bb7e2a30..7c1c19040 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -262,6 +262,8 @@ namespace q { m_expanded.push_back(r); return true; } + if (r == q) + return false; q = to_quantifier(r); } if (is_forall(q)) From 815c971c9ac85669b5f16b82821ef5a1d2d2d801 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Mar 2022 01:55:43 -0700 Subject: [PATCH 157/258] #5778 regression when tracking literal explanations --- src/ast/euf/euf_egraph.cpp | 4 ++-- src/ast/euf/euf_enode.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 652663b70..5d0bd4b17 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -298,7 +298,7 @@ namespace euf { force_push(); TRACE("euf", tout << bpp(n) << " := " << value << "\n";); n->set_value(value); - n->set_justification(j); + n->m_lit_justification = j; m_updates.push_back(update_record(n, update_record::value_assignment())); } } @@ -768,7 +768,7 @@ namespace euf { n->mark1(); if (m.is_true(n->get_expr()) || m.is_false(n->get_expr())) continue; - justification j = n->m_justification; + justification j = n->m_lit_justification; SASSERT(j.is_external()); justifications.push_back(j.ext()); } diff --git a/src/ast/euf/euf_enode.h b/src/ast/euf/euf_enode.h index dc98d95c8..7014223be 100644 --- a/src/ast/euf/euf_enode.h +++ b/src/ast/euf/euf_enode.h @@ -63,6 +63,7 @@ namespace euf { enode* m_cg = nullptr; th_var_list m_th_vars; justification m_justification; + justification m_lit_justification; unsigned m_num_args = 0; signed char m_lbl_hash = -1; // It is different from -1, if enode is used in a pattern approx_set m_lbls; From ce04c16a6fd099d0c6ba9c6a38873e341a80d9e7 Mon Sep 17 00:00:00 2001 From: John Fleisher Date: Tue, 22 Mar 2022 15:19:58 -0400 Subject: [PATCH 158/258] Jfleisher/nightlynuget (#5916) * WiP: Test nightly version number change * Fix debug assert * WiP: test nuget publish to AzDo feed for nightly build * WiP: Make Nuget deploy separate stage * WiP: fix nightly stage name * change nuget push to vstsfeed * Try case sensitive name for artifacts * WiP: use artifact folder names * add Rev version to package * WiP: build def variation on nightly build version * WiP: use Build_BuildNumber and Build_DefinitionName * WiP: using hyphen in nightly version * Tag nightly packages with datetime * fix commit * Build.BuildId and Build.DefinitionName * WiP: change suffix format to lead with alpha * test z3public feed publish * revert public publish test * WiP: test build# versioning scheme * WiP: another variant on version number for nightly Co-authored-by: jfleisher Co-authored-by: Nikolaj Bjorner --- scripts/nightly.yaml | 68 +++++++++++++++++++++++++++++----- src/api/dotnet/NativeSolver.cs | 2 +- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 04e0a8e04..f412c41f9 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,5 +1,9 @@ variables: - ReleaseVersion: '4.8.16' + + Major: '4' + Minor: '8' + Patch: '16' + NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) MacFlags: 'CXXFLAGS="-arch arm64 -arch x86_64" LINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" SLINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" FPMATH_ENABLED=False' stages: @@ -131,6 +135,8 @@ stages: targetPath: $(Build.ArtifactStagingDirectory) artifactName: 'Windows64' + + - stage: Package jobs: - job: NuGet64 @@ -171,7 +177,7 @@ stages: workingDirectory: $(Agent.TempDirectory)\package arguments: $(Agent.TempDirectory)\package - $(ReleaseVersion) + $(NightlyVersion) $(Build.Repository.Uri) $(Build.SourceBranchName) $(Build.SourceVersion) @@ -181,13 +187,17 @@ stages: displayName: 'NuGet Pack Symbols' inputs: command: custom - arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.sym.nuspec -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' + versioningScheme: byPrereleaseNumber + majorVersion: $(Major) + minorVersion: $(Minor) + patchVersion: $(Patch) + arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' - task: EsrpCodeSigning@1 displayName: 'Sign Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' FolderPath: $(Build.ArtifactStagingDirectory) - Pattern: Microsoft.Z3.$(ReleaseVersion).nupkg + Pattern: Microsoft.Z3.$(NightlyVersion).nupkg signConfigType: 'inlineSignParams' inlineOperation: | [ @@ -214,7 +224,7 @@ stages: inputs: ConnectedServiceName: 'z3-esrp-signing-2' FolderPath: $(Build.ArtifactStagingDirectory) - Pattern: Microsoft.Z3.$(ReleaseVersion).snupkg + Pattern: Microsoft.Z3.$(NightlyVersion).snupkg signConfigType: 'inlineSignParams' inlineOperation: | [ @@ -269,7 +279,7 @@ stages: workingDirectory: $(Agent.TempDirectory)\package arguments: $(Agent.TempDirectory)\package - $(ReleaseVersion) + $(NightlyVersion) $(Build.Repository.Uri) $(Build.SourceBranchName) $(Build.SourceVersion) @@ -280,13 +290,17 @@ stages: displayName: 'NuGet Pack Symbols' inputs: command: custom - arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' + versioningScheme: byPrereleaseNumber + majorVersion: $(Major) + minorVersion: $(Minor) + patchVersion: $(Patch) + arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' - task: EsrpCodeSigning@1 displayName: 'Sign Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' FolderPath: $(Build.ArtifactStagingDirectory) - Pattern: Microsoft.Z3.x86.$(ReleaseVersion).nupkg + Pattern: Microsoft.Z3.x86.$(NightlyVersion).nupkg signConfigType: 'inlineSignParams' inlineOperation: | [ @@ -313,7 +327,7 @@ stages: inputs: ConnectedServiceName: 'z3-esrp-signing-2' FolderPath: $(Build.ArtifactStagingDirectory) - Pattern: Microsoft.Z3.x86.$(ReleaseVersion).snupkg + Pattern: Microsoft.Z3.x86.$(NightlyVersion).snupkg signConfigType: 'inlineSignParams' inlineOperation: | [ @@ -449,5 +463,41 @@ stages: isDraft: false isPreRelease: true +- stage: NugetPublishNightly + jobs: + # Publish to nightly feed on Azure + - job: NuGetPublishNightly + displayName: "Push nuget packages to Azure Feed" + steps: + - task: NuGetAuthenticate@0 + displayName: 'NuGet Authenticate' + - task: NuGetToolInstaller@0 + inputs: + versionSpec: 5.x + checkLatest: false + - task: DownloadPipelineArtifact@2 + displayName: 'Download NuGet x86 Package' + inputs: + artifact: 'NuGet32' + path: $(Agent.TempDirectory)/x86 + - task: DownloadPipelineArtifact@2 + displayName: 'Download NuGet x64 Package' + inputs: + artifact: 'NuGet' + path: $(Agent.TempDirectory)/x64 + - task: NuGetCommand@2 + displayName: 'NuGet Nightly x64 push' + inputs: + command: push + publishVstsFeed: 'Z3Build/Z3-Nightly-builds' + packagesToPush: $(Agent.TempDirectory)/x64/*.nupkg + allowPackageConflicts: true + - task: NuGetCommand@2 + displayName: 'NuGet Nightly x86 push' + inputs: + command: push + publishVstsFeed: 'Z3Build/Z3-Nightly-builds' + packagesToPush: $(Agent.TempDirectory)/x86/*.nupkg + allowPackageConflicts: true # TBD: run regression tests on generated binaries. diff --git a/src/api/dotnet/NativeSolver.cs b/src/api/dotnet/NativeSolver.cs index 40444804a..7dc937234 100644 --- a/src/api/dotnet/NativeSolver.cs +++ b/src/api/dotnet/NativeSolver.cs @@ -405,7 +405,7 @@ namespace Microsoft.Z3 internal NativeSolver(NativeContext nativeCtx, Z3_solver z3solver) { - Debug.Assert(nCtx != IntPtr.Zero); + Debug.Assert(nativeCtx != null); Debug.Assert(z3solver != IntPtr.Zero); this.ntvContext = nativeCtx; From 8273a20498077fa2dce79539c261d2c563b990ef Mon Sep 17 00:00:00 2001 From: jofleish Date: Tue, 22 Mar 2022 17:26:12 -0400 Subject: [PATCH 159/258] test publish to public project feed --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index f412c41f9..a77d4a90b 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -489,14 +489,14 @@ stages: displayName: 'NuGet Nightly x64 push' inputs: command: push - publishVstsFeed: 'Z3Build/Z3-Nightly-builds' + publishVstsFeed: 'Z3 Public Nuget/Z3-Public-Nightly' packagesToPush: $(Agent.TempDirectory)/x64/*.nupkg allowPackageConflicts: true - task: NuGetCommand@2 displayName: 'NuGet Nightly x86 push' inputs: command: push - publishVstsFeed: 'Z3Build/Z3-Nightly-builds' + publishVstsFeed: 'Z3 Public Nuget/Z3-Public-Nightly' packagesToPush: $(Agent.TempDirectory)/x86/*.nupkg allowPackageConflicts: true From a24a9226883dd697548f0cc7662e43a6894d2d0c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Mar 2022 16:03:35 -0700 Subject: [PATCH 160/258] fix #5915 --- examples/java/JavaExample.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index bd705456f..150efd545 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -1868,7 +1868,7 @@ class JavaExample } } else { - System.out.println("BUG, the constraints are satisfiable."); + System.out.println("BUG, the constraints are not satisfiable."); } } From 7bf2df1b7afe4f3fb4e6dbbd6783ec67a8381694 Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 08:44:42 -0400 Subject: [PATCH 161/258] Update nightly nuget service connection --- scripts/nightly.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index a77d4a90b..5be572a6a 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -3,7 +3,7 @@ variables: Major: '4' Minor: '8' Patch: '16' - NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) + NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildNumber)-$(Build.DefinitionName) MacFlags: 'CXXFLAGS="-arch arm64 -arch x86_64" LINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" SLINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" FPMATH_ENABLED=False' stages: @@ -471,6 +471,7 @@ stages: steps: - task: NuGetAuthenticate@0 displayName: 'NuGet Authenticate' + inputs: 'Z3-nightly public nuget feed' - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x From 16f47954c073432895947eeee4c59f9a861cc312 Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 08:50:14 -0400 Subject: [PATCH 162/258] Use camel case service name --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 5be572a6a..e0b7d1bb7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -471,7 +471,7 @@ stages: steps: - task: NuGetAuthenticate@0 displayName: 'NuGet Authenticate' - inputs: 'Z3-nightly public nuget feed' + inputs: Z3NightlyNuget - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x From 13a33a3966b364a455aacbdac3e94e25baa2dd79 Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 08:51:20 -0400 Subject: [PATCH 163/258] fix authentication input --- scripts/nightly.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e0b7d1bb7..2bd47f9ba 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -471,7 +471,8 @@ stages: steps: - task: NuGetAuthenticate@0 displayName: 'NuGet Authenticate' - inputs: Z3NightlyNuget + inputs: + nuGetServiceConnections: Z3NightlyNuget - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x From d9e93d5f7cd45923a7fdb429f35712dbb96d826e Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 09:53:15 -0400 Subject: [PATCH 164/258] revert to buildid in version number --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 2bd47f9ba..a4c8cd5af 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -3,7 +3,7 @@ variables: Major: '4' Minor: '8' Patch: '16' - NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildNumber)-$(Build.DefinitionName) + NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) MacFlags: 'CXXFLAGS="-arch arm64 -arch x86_64" LINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" SLINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" FPMATH_ENABLED=False' stages: From 1ee3de540934a5c47a7ed72a7eca3de1b008f280 Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 12:25:31 -0400 Subject: [PATCH 165/258] temporary workaround for build --- scripts/nightly.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index a4c8cd5af..4ec6fbe8c 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -439,19 +439,19 @@ stages: inputs: artifactName: 'NuGet32' targetPath: tmp - - task: GitHubRelease@0 - inputs: - gitHubConnection: Z3GitHub - repositoryName: 'Z3Prover/z3' - action: 'delete' -# target: '$(Build.SourceVersion)' - tagSource: 'manual' - tag: 'Nightly' - - task: GitHubRelease@0 - inputs: - gitHubConnection: Z3GitHub - repositoryName: 'Z3Prover/z3' - action: 'create' +# - task: GitHubRelease@0 +# inputs: +# gitHubConnection: Z3GitHub +# repositoryName: 'Z3Prover/z3' +# action: 'delete' +# # target: '$(Build.SourceVersion)' +# tagSource: 'manual' +# tag: 'Nightly' +# - task: GitHubRelease@0 +# inputs: +# gitHubConnection: Z3GitHub +# repositoryName: 'Z3Prover/z3' +# action: 'create' # target: '$(Build.SourceVersion)' tagSource: 'manual' tag: 'Nightly' From 3ffc3c2f9786b96667dd4b700d839eacc49051d9 Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 12:30:52 -0400 Subject: [PATCH 166/258] continue on github tagging error --- scripts/nightly.yaml | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4ec6fbe8c..12a9f68a3 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -439,19 +439,20 @@ stages: inputs: artifactName: 'NuGet32' targetPath: tmp -# - task: GitHubRelease@0 -# inputs: -# gitHubConnection: Z3GitHub -# repositoryName: 'Z3Prover/z3' -# action: 'delete' -# # target: '$(Build.SourceVersion)' -# tagSource: 'manual' -# tag: 'Nightly' -# - task: GitHubRelease@0 -# inputs: -# gitHubConnection: Z3GitHub -# repositoryName: 'Z3Prover/z3' -# action: 'create' + - task: GitHubRelease@0 + inputs: + gitHubConnection: Z3GitHub + repositoryName: 'Z3Prover/z3' + action: 'delete' +# target: '$(Build.SourceVersion)' + tagSource: 'manual' + tag: 'Nightly' + continueOnError: true + - task: GitHubRelease@0 + inputs: + gitHubConnection: Z3GitHub + repositoryName: 'Z3Prover/z3' + action: 'create' # target: '$(Build.SourceVersion)' tagSource: 'manual' tag: 'Nightly' @@ -462,6 +463,7 @@ stages: assetUploadMode: 'replace' isDraft: false isPreRelease: true + continueOnError: true - stage: NugetPublishNightly jobs: From b8c61ca27811ffed8553f44cafb09db645ae688a Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 12:31:35 -0400 Subject: [PATCH 167/258] continue on error in deploy --- scripts/nightly.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 12a9f68a3..e7730182a 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -396,6 +396,7 @@ stages: jobs: - job: Deploy displayName: "Deploy into GitHub" + continueOnError: true pool: vmImage: "ubuntu-latest" steps: From d790523c592a384933e9120a8900c9703bd74976 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Mar 2022 09:49:44 -0700 Subject: [PATCH 168/258] #5917 Add model.user_functions (default true) to control whether user functions are added to the model. --- src/cmd_context/cmd_context.cpp | 3 +++ src/model/model_params.pyg | 1 + src/smt/smt_context.cpp | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 968dcacd8..89efc439f 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1815,6 +1815,9 @@ void cmd_context::display_model(model_ref& mdl) { } void cmd_context::add_declared_functions(model& mdl) { + model_params p; + if (!p.user_functions()) + return; for (auto const& kv : m_func_decls) { func_decl* f = kv.m_value.first(); if (f->get_family_id() == null_family_id && !mdl.has_interpretation(f)) { diff --git a/src/model/model_params.pyg b/src/model/model_params.pyg index 7e370cb3a..59899644e 100644 --- a/src/model/model_params.pyg +++ b/src/model/model_params.pyg @@ -5,6 +5,7 @@ def_module_params('model', ('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'), ('compact', BOOL, True, 'try to compact function graph (i.e., function interpretations that are lookup tables)'), ('inline_def', BOOL, False, 'inline local function definitions ignoring possible expansion'), + ('user_functions', BOOL, True, 'include user defined functions in model'), ('completion', BOOL, False, 'enable/disable model completion'), )) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 2eba2c2a2..a7946a676 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -29,6 +29,7 @@ Revision History: #include "ast/proofs/proof_checker.h" #include "ast/ast_util.h" #include "ast/well_sorted.h" +#include "model/model_params.hpp" #include "model/model.h" #include "model/model_pp.h" #include "smt/smt_context.h" @@ -4638,7 +4639,8 @@ namespace smt { } void context::add_rec_funs_to_model() { - if (m_model) + model_params p; + if (m_model && p.user_functions()) m_model->add_rec_funs(); } From 365b8f328179da0ceb3545dbafb327bdee0c8b47 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Mar 2022 09:51:06 -0700 Subject: [PATCH 169/258] change default to _not_ include auxiliary functions in model as this seems to break fewer' Signed-off-by: Nikolaj Bjorner --- src/model/model_params.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/model_params.pyg b/src/model/model_params.pyg index 59899644e..730b574ac 100644 --- a/src/model/model_params.pyg +++ b/src/model/model_params.pyg @@ -5,7 +5,7 @@ def_module_params('model', ('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'), ('compact', BOOL, True, 'try to compact function graph (i.e., function interpretations that are lookup tables)'), ('inline_def', BOOL, False, 'inline local function definitions ignoring possible expansion'), - ('user_functions', BOOL, True, 'include user defined functions in model'), + ('user_functions', BOOL, False, 'include user defined functions in model'), ('completion', BOOL, False, 'enable/disable model completion'), )) From bb4a2b97b67abdafe73c89af354e90cc2bbd7565 Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 14:28:43 -0400 Subject: [PATCH 170/258] remove project from public/org level feed --- scripts/nightly.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e7730182a..dca77a731 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -474,8 +474,6 @@ stages: steps: - task: NuGetAuthenticate@0 displayName: 'NuGet Authenticate' - inputs: - nuGetServiceConnections: Z3NightlyNuget - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x @@ -494,14 +492,14 @@ stages: displayName: 'NuGet Nightly x64 push' inputs: command: push - publishVstsFeed: 'Z3 Public Nuget/Z3-Public-Nightly' + publishVstsFeed: 'Z3-Public-Nightly' packagesToPush: $(Agent.TempDirectory)/x64/*.nupkg allowPackageConflicts: true - task: NuGetCommand@2 displayName: 'NuGet Nightly x86 push' inputs: command: push - publishVstsFeed: 'Z3 Public Nuget/Z3-Public-Nightly' + publishVstsFeed: 'Z3-Public-Nightly' packagesToPush: $(Agent.TempDirectory)/x86/*.nupkg allowPackageConflicts: true From 32233e1bf1b62afd98407e16efb9df1318e6caad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Mar 2022 12:20:53 -0700 Subject: [PATCH 171/258] set default to true to avoid regression failures Signed-off-by: Nikolaj Bjorner --- src/model/model_params.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/model_params.pyg b/src/model/model_params.pyg index 730b574ac..59899644e 100644 --- a/src/model/model_params.pyg +++ b/src/model/model_params.pyg @@ -5,7 +5,7 @@ def_module_params('model', ('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'), ('compact', BOOL, True, 'try to compact function graph (i.e., function interpretations that are lookup tables)'), ('inline_def', BOOL, False, 'inline local function definitions ignoring possible expansion'), - ('user_functions', BOOL, False, 'include user defined functions in model'), + ('user_functions', BOOL, True, 'include user defined functions in model'), ('completion', BOOL, False, 'enable/disable model completion'), )) From a4af26e2f02fe274882f750b5871811db67446a9 Mon Sep 17 00:00:00 2001 From: jofleish Date: Wed, 23 Mar 2022 16:25:34 -0400 Subject: [PATCH 172/258] Shorten public feed to Z3Nightly --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index dca77a731..5998525dc 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -492,14 +492,14 @@ stages: displayName: 'NuGet Nightly x64 push' inputs: command: push - publishVstsFeed: 'Z3-Public-Nightly' + publishVstsFeed: 'Z3Nightly' packagesToPush: $(Agent.TempDirectory)/x64/*.nupkg allowPackageConflicts: true - task: NuGetCommand@2 displayName: 'NuGet Nightly x86 push' inputs: command: push - publishVstsFeed: 'Z3-Public-Nightly' + publishVstsFeed: 'Z3Nightly' packagesToPush: $(Agent.TempDirectory)/x86/*.nupkg allowPackageConflicts: true From 42da9760f904784c964c2fc2e7f503634105073e Mon Sep 17 00:00:00 2001 From: jofleish Date: Thu, 24 Mar 2022 12:35:10 -0400 Subject: [PATCH 173/258] Continue on error in GitHub tagging --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 5998525dc..ab59ee004 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -441,6 +441,7 @@ stages: artifactName: 'NuGet32' targetPath: tmp - task: GitHubRelease@0 + continueOnError: true inputs: gitHubConnection: Z3GitHub repositoryName: 'Z3Prover/z3' @@ -448,8 +449,8 @@ stages: # target: '$(Build.SourceVersion)' tagSource: 'manual' tag: 'Nightly' - continueOnError: true - task: GitHubRelease@0 + continueOnError: true inputs: gitHubConnection: Z3GitHub repositoryName: 'Z3Prover/z3' @@ -464,7 +465,6 @@ stages: assetUploadMode: 'replace' isDraft: false isPreRelease: true - continueOnError: true - stage: NugetPublishNightly jobs: From 3828130791bf8e60038b46b0d6602cb7e43fb344 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Mar 2022 14:05:05 -1000 Subject: [PATCH 174/258] fix #5922 use 0u to help type inference Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b00a33ad7..4d60de433 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2333,7 +2333,7 @@ namespace z3 { inline expr pble(expr_vector const& es, int const* coeffs, int bound) { assert(es.size() > 0); - context& ctx = es[0].ctx(); + context& ctx = es[0u].ctx(); array _es(es); Z3_ast r = Z3_mk_pble(ctx, _es.size(), _es.ptr(), coeffs, bound); ctx.check_error(); @@ -2341,7 +2341,7 @@ namespace z3 { } inline expr pbge(expr_vector const& es, int const* coeffs, int bound) { assert(es.size() > 0); - context& ctx = es[0].ctx(); + context& ctx = es[0u].ctx(); array _es(es); Z3_ast r = Z3_mk_pbge(ctx, _es.size(), _es.ptr(), coeffs, bound); ctx.check_error(); @@ -2349,7 +2349,7 @@ namespace z3 { } inline expr pbeq(expr_vector const& es, int const* coeffs, int bound) { assert(es.size() > 0); - context& ctx = es[0].ctx(); + context& ctx = es[0u].ctx(); array _es(es); Z3_ast r = Z3_mk_pbeq(ctx, _es.size(), _es.ptr(), coeffs, bound); ctx.check_error(); @@ -2357,7 +2357,7 @@ namespace z3 { } inline expr atmost(expr_vector const& es, unsigned bound) { assert(es.size() > 0); - context& ctx = es[0].ctx(); + context& ctx = es[0u].ctx(); array _es(es); Z3_ast r = Z3_mk_atmost(ctx, _es.size(), _es.ptr(), bound); ctx.check_error(); @@ -2365,7 +2365,7 @@ namespace z3 { } inline expr atleast(expr_vector const& es, unsigned bound) { assert(es.size() > 0); - context& ctx = es[0].ctx(); + context& ctx = es[0u].ctx(); array _es(es); Z3_ast r = Z3_mk_atleast(ctx, _es.size(), _es.ptr(), bound); ctx.check_error(); @@ -2373,7 +2373,7 @@ namespace z3 { } inline expr sum(expr_vector const& args) { assert(args.size() > 0); - context& ctx = args[0].ctx(); + context& ctx = args[0u].ctx(); array _args(args); Z3_ast r = Z3_mk_add(ctx, _args.size(), _args.ptr()); ctx.check_error(); @@ -2382,7 +2382,7 @@ namespace z3 { inline expr distinct(expr_vector const& args) { assert(args.size() > 0); - context& ctx = args[0].ctx(); + context& ctx = args[0u].ctx(); array _args(args); Z3_ast r = Z3_mk_distinct(ctx, _args.size(), _args.ptr()); ctx.check_error(); @@ -2411,14 +2411,14 @@ namespace z3 { Z3_ast r; assert(args.size() > 0); if (args.size() == 1) { - return args[0]; + return args[0u]; } - context& ctx = args[0].ctx(); + context& ctx = args[0u].ctx(); array _args(args); - if (Z3_is_seq_sort(ctx, args[0].get_sort())) { + if (Z3_is_seq_sort(ctx, args[0u].get_sort())) { r = Z3_mk_seq_concat(ctx, _args.size(), _args.ptr()); } - else if (Z3_is_re_sort(ctx, args[0].get_sort())) { + else if (Z3_is_re_sort(ctx, args[0u].get_sort())) { r = Z3_mk_re_concat(ctx, _args.size(), _args.ptr()); } else { @@ -2448,7 +2448,7 @@ namespace z3 { inline expr mk_xor(expr_vector const& args) { if (args.empty()) return args.ctx().bool_val(false); - expr r = args[0]; + expr r = args[0u]; for (unsigned i = 1; i < args.size(); ++i) r = r ^ args[i]; return r; @@ -2771,7 +2771,7 @@ namespace z3 { assert(!m_end && !m_empty); m_cube = m_solver.cube(m_vars, m_cutoff); m_cutoff = 0xFFFFFFFF; - if (m_cube.size() == 1 && m_cube[0].is_false()) { + if (m_cube.size() == 1 && m_cube[0u].is_false()) { m_cube = z3::expr_vector(m_solver.ctx()); m_end = true; } @@ -3005,7 +3005,7 @@ namespace z3 { } array buffer(n); for (unsigned i = 0; i < n; ++i) buffer[i] = tactics[i]; - return tactic(tactics[0].ctx(), Z3_tactic_par_or(tactics[0].ctx(), n, buffer.ptr())); + return tactic(tactics[0u].ctx(), Z3_tactic_par_or(tactics[0u].ctx(), n, buffer.ptr())); } inline tactic par_and_then(tactic const & t1, tactic const & t2) { @@ -3804,7 +3804,7 @@ namespace z3 { } inline expr re_intersect(expr_vector const& args) { assert(args.size() > 0); - context& ctx = args[0].ctx(); + context& ctx = args[0u].ctx(); array _args(args); Z3_ast r = Z3_mk_re_intersect(ctx, _args.size(), _args.ptr()); ctx.check_error(); From 7bb969ab52b5ce55bc5b03c0c66e7b6f84bc6ac8 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Sun, 27 Mar 2022 04:36:15 +0200 Subject: [PATCH 175/258] Fixed problem with registering bitvector functions (#5923) --- src/smt/smt_context.cpp | 2 +- src/smt/smt_context.h | 2 +- src/smt/theory_user_propagator.cpp | 8 ++++---- src/smt/theory_user_propagator.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a7946a676..377ad1f2b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -206,7 +206,7 @@ namespace smt { ast_translation tr(src_ctx.m, m, false); for (unsigned i = 0; i < src_ctx.m_user_propagator->get_num_vars(); ++i) { app* e = src_ctx.m_user_propagator->get_expr(i); - m_user_propagator->add_expr(tr(e)); + m_user_propagator->add_expr(tr(e), true); } } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index f1b2514b1..ac2b0cfc8 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1729,7 +1729,7 @@ namespace smt { void user_propagate_register_expr(expr* e) { if (!m_user_propagator) throw default_exception("user propagator must be initialized"); - m_user_propagator->add_expr(e); + m_user_propagator->add_expr(e, true); } void user_propagate_register_created(user_propagator::created_eh_t& r) { diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 3f5310ce5..08170d4eb 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -39,7 +39,7 @@ void theory_user_propagator::force_push() { } } -void theory_user_propagator::add_expr(expr* term) { +void theory_user_propagator::add_expr(expr* term, bool ensure_enode) { force_push(); expr_ref r(m); expr* e = term; @@ -52,7 +52,7 @@ void theory_user_propagator::add_expr(expr* term) { e = r; ctx.mark_as_relevant(eq.get()); } - enode* n = ensure_enode(e); + enode* n = ensure_enode ? this->ensure_enode(e) : ctx.get_enode(e); if (is_attached_to_var(n)) return; @@ -90,7 +90,7 @@ void theory_user_propagator::propagate_cb( } void theory_user_propagator::register_cb(expr* e) { - add_expr(e); + add_expr(e, true); } theory * theory_user_propagator::mk_fresh(context * new_ctx) { @@ -243,7 +243,7 @@ bool theory_user_propagator::internalize_term(app* term) { if (term->get_family_id() == get_id() && !ctx.e_internalized(term)) ctx.mk_enode(term, true, false, true); - add_expr(term); + add_expr(term, false); if (!m_created_eh) throw default_exception("You have to register a created event handler for new terms if you track them"); diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index 1045feb0a..d3194a3fe 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -110,7 +110,7 @@ namespace smt { m_fresh_eh = fresh_eh; } - void add_expr(expr* e); + void add_expr(expr* e, bool ensure_enode); void register_final(user_propagator::final_eh_t& final_eh) { m_final_eh = final_eh; } void register_fixed(user_propagator::fixed_eh_t& fixed_eh) { m_fixed_eh = fixed_eh; } From a9a843294e3a80692fba6f7fb346eef7e62f76bc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Mar 2022 17:10:23 -1000 Subject: [PATCH 176/258] try add ARM path for MacOS Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 45 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index ab59ee004..5cce4853f 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -4,7 +4,8 @@ variables: Minor: '8' Patch: '16' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) - MacFlags: 'CXXFLAGS="-arch arm64 -arch x86_64" LINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" SLINK_EXTRA_FLAGS="-arch arm64 -arch x86_64" FPMATH_ENABLED=False' + MacFlags: 'CXXFLAGS="-arch x86_64" LINK_EXTRA_FLAGS="-arch x86_64" SLINK_EXTRA_FLAGS="-arch x86_64" + MacArmFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64" FPMATH_ENABLED=False' stages: - stage: Build @@ -24,6 +25,20 @@ stages: artifactName: 'Mac' targetPath: $(Build.ArtifactStagingDirectory) + - job: MacArm + displayName: "Mac Build" + pool: + vmImage: "macOS-latest" + steps: + - script: $(MacArmFlags) python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - script: git clone https://github.com/z3prover/z3test z3test + - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 + - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'MacArm' + targetPath: $(Build.ArtifactStagingDirectory) + - job: Ubuntu displayName: "Ubuntu build" pool: @@ -165,6 +180,11 @@ stages: inputs: artifact: 'Mac' path: $(Agent.TempDirectory)\package + - task: DownloadPipelineArtifact@2 + displayName: 'Download macOS ARM Build' + inputs: + artifact: 'MacArm' + path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x @@ -392,6 +412,24 @@ stages: artifactName: 'Python packages' targetPath: src/api/python/dist + - job: PythonArm + displayName: "Python Arm packaging" + pool: + vmImage: "ubuntu-latest" + steps: + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: 'MacArm' + targetPath: $(Agent.TempDirectory) + - script: cd $(Agent.TempDirectory); mkdir osx-arm-bin; cd osx-arm-bin; unzip ../*osx*.zip + - script: python3 -m pip install --user -U setuptools wheel + - script: cd src/api/python; python3 setup.py sdist + - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-arm-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'Python Arm packages' + targetPath: src/api/python/dist + - stage: Deployment jobs: - job: Deploy @@ -430,6 +468,11 @@ stages: inputs: artifactName: 'Python packages' targetPath: tmp + - task: DownloadPipelineArtifact@2 + displayName: "Download Python Arm" + inputs: + artifactName: 'Python Arm packages' + targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download NuGet" inputs: From ae07a537640e5ebed1e262727e06f4fd8115354a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Mar 2022 17:14:31 -1000 Subject: [PATCH 177/258] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 5cce4853f..023036833 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -4,7 +4,7 @@ variables: Minor: '8' Patch: '16' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) - MacFlags: 'CXXFLAGS="-arch x86_64" LINK_EXTRA_FLAGS="-arch x86_64" SLINK_EXTRA_FLAGS="-arch x86_64" + MacFlags: 'CXXFLAGS="-arch x86_64" LINK_EXTRA_FLAGS="-arch x86_64" SLINK_EXTRA_FLAGS="-arch x86_64"' MacArmFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64" FPMATH_ENABLED=False' stages: From da00deead895ccb51ec6c2d637922857b84f0da4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 Mar 2022 17:39:53 -1000 Subject: [PATCH 178/258] disable arm Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 023036833..c5c788072 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -26,6 +26,7 @@ stages: targetPath: $(Build.ArtifactStagingDirectory) - job: MacArm + condition: eq(0,1) displayName: "Mac Build" pool: vmImage: "macOS-latest" @@ -180,11 +181,11 @@ stages: inputs: artifact: 'Mac' path: $(Agent.TempDirectory)\package - - task: DownloadPipelineArtifact@2 - displayName: 'Download macOS ARM Build' - inputs: - artifact: 'MacArm' - path: $(Agent.TempDirectory)\package +# - task: DownloadPipelineArtifact@2 +# displayName: 'Download macOS ARM Build' +# inputs: +# artifact: 'MacArm' +# path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x @@ -413,6 +414,7 @@ stages: targetPath: src/api/python/dist - job: PythonArm + condition eq(0,1) displayName: "Python Arm packaging" pool: vmImage: "ubuntu-latest" From cb1e16fd76dc2f35ef3a7f290a4e0bab10fe97f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 Mar 2022 17:42:16 -1000 Subject: [PATCH 179/258] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index c5c788072..e25a4cece 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -414,7 +414,7 @@ stages: targetPath: src/api/python/dist - job: PythonArm - condition eq(0,1) + condition: eq(0,1) displayName: "Python Arm packaging" pool: vmImage: "ubuntu-latest" From 431c3af4099c51d145be69917f9b0a5b85bb5ad2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 Mar 2022 18:23:41 -1000 Subject: [PATCH 180/258] fix #5929 - add parameter bv_le2extract to allow disabling the disassembly to extract --- src/ast/rewriter/bv_rewriter.cpp | 3 ++- src/ast/rewriter/bv_rewriter.h | 1 + src/params/bv_rewriter_params.pyg | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index d7ba4d604..073885c21 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -37,6 +37,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) { m_extract_prop = p.bv_extract_prop(); m_ite2id = p.bv_ite2id(); m_le_extra = p.bv_le_extra(); + m_le2extract = p.bv_le2extract(); set_sort_sums(p.bv_sort_ac()); } @@ -577,7 +578,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref result = m().mk_eq(a, m_util.mk_numeral(numeral(0), bv_sz)); return BR_REWRITE1; } - else if (first_non_zero < bv_sz - 1) { + else if (first_non_zero < bv_sz - 1 && m_le2extract) { result = m().mk_and(m().mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)), m_util.mk_ule(m_mk_extract(first_non_zero, 0, a), m_mk_extract(first_non_zero, 0, b))); return BR_REWRITE3; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 7b734dca1..7f0c67540 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -62,6 +62,7 @@ class bv_rewriter : public poly_rewriter { bool m_extract_prop; bool m_bvnot_simpl; bool m_le_extra; + bool m_le2extract; bool is_zero_bit(expr * x, unsigned idx); diff --git a/src/params/bv_rewriter_params.pyg b/src/params/bv_rewriter_params.pyg index b439f2924..04c582485 100644 --- a/src/params/bv_rewriter_params.pyg +++ b/src/params/bv_rewriter_params.pyg @@ -11,5 +11,6 @@ def_module_params(module_name='rewriter', ("bv_extract_prop", BOOL, False, "attempt to partially propagate extraction inwards"), ("bv_not_simpl", BOOL, False, "apply simplifications for bvnot"), ("bv_ite2id", BOOL, False, "rewrite ite that can be simplified to identity"), - ("bv_le_extra", BOOL, False, "additional bu_(u/s)le simplifications") + ("bv_le_extra", BOOL, False, "additional bu_(u/s)le simplifications"), + ("bv_le2extract", BOOL, True, "disassemble bvule to extract") )) From b0605a9d364d4d89e42713dd60baec604981aea2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 Mar 2022 18:29:55 -1000 Subject: [PATCH 181/258] Update nightly.yaml --- scripts/nightly.yaml | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e25a4cece..374249432 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -5,7 +5,6 @@ variables: Patch: '16' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) MacFlags: 'CXXFLAGS="-arch x86_64" LINK_EXTRA_FLAGS="-arch x86_64" SLINK_EXTRA_FLAGS="-arch x86_64"' - MacArmFlags: 'CXXFLAGS="-arch arm64" LINK_EXTRA_FLAGS="-arch arm64" SLINK_EXTRA_FLAGS="-arch arm64" FPMATH_ENABLED=False' stages: - stage: Build @@ -25,20 +24,6 @@ stages: artifactName: 'Mac' targetPath: $(Build.ArtifactStagingDirectory) - - job: MacArm - condition: eq(0,1) - displayName: "Mac Build" - pool: - vmImage: "macOS-latest" - steps: - - script: $(MacArmFlags) python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - - script: git clone https://github.com/z3prover/z3test z3test - - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - - task: PublishPipelineArtifact@1 - inputs: - artifactName: 'MacArm' - targetPath: $(Build.ArtifactStagingDirectory) - job: Ubuntu displayName: "Ubuntu build" @@ -181,11 +166,6 @@ stages: inputs: artifact: 'Mac' path: $(Agent.TempDirectory)\package -# - task: DownloadPipelineArtifact@2 -# displayName: 'Download macOS ARM Build' -# inputs: -# artifact: 'MacArm' -# path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x @@ -413,24 +393,6 @@ stages: artifactName: 'Python packages' targetPath: src/api/python/dist - - job: PythonArm - condition: eq(0,1) - displayName: "Python Arm packaging" - pool: - vmImage: "ubuntu-latest" - steps: - - task: DownloadPipelineArtifact@2 - inputs: - artifactName: 'MacArm' - targetPath: $(Agent.TempDirectory) - - script: cd $(Agent.TempDirectory); mkdir osx-arm-bin; cd osx-arm-bin; unzip ../*osx*.zip - - script: python3 -m pip install --user -U setuptools wheel - - script: cd src/api/python; python3 setup.py sdist - - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-arm-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - task: PublishPipelineArtifact@0 - inputs: - artifactName: 'Python Arm packages' - targetPath: src/api/python/dist - stage: Deployment jobs: @@ -470,11 +432,6 @@ stages: inputs: artifactName: 'Python packages' targetPath: tmp - - task: DownloadPipelineArtifact@2 - displayName: "Download Python Arm" - inputs: - artifactName: 'Python Arm packages' - targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download NuGet" inputs: From dd27f7e9378ba5df6545414a71338b33a30b081e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Mar 2022 17:47:48 -1000 Subject: [PATCH 182/258] #5935 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index c86db1aa5..330a608a4 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1542,8 +1542,8 @@ bool theory_seq::add_length_to_eqc(expr* e) { expr* o = n->get_expr(); if (!has_length(o)) { expr_ref len(m_util.str.mk_length(o), m); - ensure_enode(len); add_length(len); + ensure_enode(len); change = true; } n = n->get_next(); From 28e94583da0974894b74a351fe215d44dc680840 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Mar 2022 21:49:08 -0700 Subject: [PATCH 183/258] break self recursion #5937 --- src/model/datatype_factory.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/model/datatype_factory.cpp b/src/model/datatype_factory.cpp index b77512cb8..7ca3b5699 100644 --- a/src/model/datatype_factory.cpp +++ b/src/model/datatype_factory.cpp @@ -48,10 +48,8 @@ expr * datatype_factory::get_some_value(sort * s) { */ expr * datatype_factory::get_last_fresh_value(sort * s) { expr * val = nullptr; - if (m_last_fresh_value.find(s, val)) { - TRACE("datatype", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";); + if (m_last_fresh_value.find(s, val)) return val; - } value_set * set = get_value_set(s); if (set->empty()) val = get_some_value(s); @@ -200,7 +198,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { if (m_util.is_recursive(s)) { while (true) { ++num_iterations; - TRACE("datatype", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); + TRACE("datatype", tout << num_iterations << " " << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); ptr_vector const & constructors = *m_util.get_datatype_constructors(s); for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); @@ -219,7 +217,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { expr * maybe_new_arg = nullptr; if (!m_util.is_datatype(s_arg)) maybe_new_arg = m_model.get_fresh_value(s_arg); - else if (num_iterations <= 1) + else if (num_iterations <= 1 || s == s_arg) maybe_new_arg = get_almost_fresh_value(s_arg); else maybe_new_arg = get_fresh_value(s_arg); From 5154295202100d561bc3a1355bb12ac3aeb25154 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Mar 2022 23:18:03 -0700 Subject: [PATCH 184/258] #5932 --- src/qe/qe.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index da0ea8cf7..509b73835 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1484,13 +1484,11 @@ namespace qe { tout << "free: " << m_free_vars << "\n";); free_vars.append(m_free_vars); - if (!m_free_vars.empty() || m_solver.inconsistent()) { - if (m_fml.get() != m_subfml.get()) { - scoped_ptr rp = mk_default_expr_replacer(m, false); - rp->apply_substitution(to_app(m_subfml.get()), fml, m_fml); - fml = m_fml; - } + if (m_fml.get() != m_subfml.get()) { + scoped_ptr rp = mk_default_expr_replacer(m, false); + rp->apply_substitution(to_app(m_subfml.get()), fml, m_fml); + fml = m_fml; } reset(); m_solver.pop(1); From 81084b8232cd9e2ec85d0d96e8d34ce3b16e86d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Apr 2022 13:07:17 -0700 Subject: [PATCH 185/258] #5778 #5937 --- src/model/datatype_factory.cpp | 2 +- src/sat/smt/array_model.cpp | 166 ++++++++++++++++++++++----------- src/sat/smt/array_solver.h | 29 ++++++ src/sat/smt/sat_th.h | 1 + src/smt/theory_arith.h | 4 +- src/smt/theory_arith_core.h | 53 ++++++++--- 6 files changed, 186 insertions(+), 69 deletions(-) diff --git a/src/model/datatype_factory.cpp b/src/model/datatype_factory.cpp index 7ca3b5699..e58812a1f 100644 --- a/src/model/datatype_factory.cpp +++ b/src/model/datatype_factory.cpp @@ -217,7 +217,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { expr * maybe_new_arg = nullptr; if (!m_util.is_datatype(s_arg)) maybe_new_arg = m_model.get_fresh_value(s_arg); - else if (num_iterations <= 1 || s == s_arg) + else if (num_iterations <= 1 || m_util.is_recursive(s_arg)) maybe_new_arg = get_almost_fresh_value(s_arg); else maybe_new_arg = get_fresh_value(s_arg); diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index 1f1066121..cb9ffe229 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -24,6 +24,11 @@ namespace array { void solver::init_model() { collect_defaults(); + collect_selects(); + } + + void solver::finalize_model(model& mdl) { + std::for_each(m_selects_range.begin(), m_selects_range.end(), delete_proc()); } bool solver::add_dep(euf::enode* n, top_sort& dep) { @@ -103,17 +108,15 @@ namespace array { if (!get_else(v) && fi->get_else()) set_else(v, fi->get_else()); - - for (euf::enode* p : euf::enode_parents(n)) { - if (a.is_select(p->get_expr()) && p->get_arg(0)->get_root() == n) { - expr* value = values.get(p->get_root_id(), nullptr); - if (!value || value == fi->get_else()) - continue; - args.reset(); - for (unsigned i = 1; i < p->num_args(); ++i) - args.push_back(values.get(p->get_arg(i)->get_root_id())); - fi->insert_entry(args.data(), value); - } + + for (euf::enode* p : *get_select_set(n)) { + expr* value = values.get(p->get_root_id(), nullptr); + if (!value || value == fi->get_else()) + continue; + args.reset(); + for (unsigned i = 1; i < p->num_args(); ++i) + args.push_back(values.get(p->get_arg(i)->get_root_id())); + fi->insert_entry(args.data(), value); } TRACE("array", tout << "array-as-function " << ctx.bpp(n) << " := " << mk_pp(f, m) << "\n" << "default " << mk_pp(fi->get_else(), m) << "\n";); @@ -135,52 +138,103 @@ namespace array { return true; return false; -#if 0 - struct eq { - solver& s; - eq(solver& s) :s(s) {} - bool operator()(euf::enode* n1, euf::enode* n2) const { - SASSERT(s.a.is_select(n1->get_expr())); - SASSERT(s.a.is_select(n2->get_expr())); - for (unsigned i = n1->num_args(); i-- > 1; ) - if (n1->get_arg(i)->get_root() != n2->get_arg(i)->get_root()) - return false; - return true; - } - }; - struct hash { - solver& s; - hash(solver& s) :s(s) {} - unsigned operator()(euf::enode* n) const { - SASSERT(s.a.is_select(n->get_expr())); - unsigned h = 33; - for (unsigned i = n->num_args(); i-- > 1; ) - h = hash_u_u(h, n->get_arg(i)->get_root_id()); - return h; - } - }; - eq eq_proc(*this); - hash hash_proc(*this); - hashtable table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, hash_proc, eq_proc); - euf::enode* p2 = nullptr; - auto maps_diff = [&](euf::enode* p, euf::enode* else_, euf::enode* r) { - return table.find(p, p2) ? p2->get_root() != r : (else_ && else_ != r); - }; - auto table_diff = [&](euf::enode* r1, euf::enode* r2, euf::enode* else1) { - table.reset(); - for (euf::enode* p : euf::enode_parents(r1)) - if (a.is_select(p->get_expr()) && r1 == p->get_arg(0)->get_root()) - table.insert(p); - for (euf::enode* p : euf::enode_parents(r2)) - if (a.is_select(p->get_expr()) && r2 == p->get_arg(0)->get_root()) - if (maps_diff(p, else1, p->get_root())) - return true; - return false; - }; - - return table_diff(r1, r2, else1) || table_diff(r2, r1, else2); + } -#endif + unsigned solver::sel_hash::operator()(euf::enode * n) const { + return get_composite_hash(n, n->num_args() - 1, sel_khasher(), sel_chasher()); + } + + bool solver::sel_eq::operator()(euf::enode * n1, euf::enode * n2) const { + SASSERT(n1->num_args() == n2->num_args()); + unsigned num_args = n1->num_args(); + for (unsigned i = 1; i < num_args; i++) + if (n1->get_arg(i)->get_root() != n2->get_arg(i)->get_root()) + return false; + return true; + } + + + void solver::collect_selects() { + int num_vars = get_num_vars(); + + m_selects.reset(); + m_selects_domain.reset(); + m_selects_range.reset(); + + for (theory_var v = 0; v < num_vars; ++v) { + euf::enode * r = var2enode(v)->get_root(); + if (is_representative(v) && ctx.is_relevant(r)) { + for (euf::enode * parent : euf::enode_parents(r)) { + if (parent->get_cg() == parent && + ctx.is_relevant(parent) && + a.is_select(parent->get_expr()) && + parent->get_arg(0)->get_root() == r) { + select_set * s = get_select_set(r); + SASSERT(!s->contains(parent) || (*(s->find(parent)))->get_root() == parent->get_root()); + s->insert(parent); + } + } + } + } + euf::enode_pair_vector todo; + for (euf::enode * r : m_selects_domain) + for (euf::enode* sel : *get_select_set(r)) + propagate_select_to_store_parents(r, sel, todo); + for (unsigned qhead = 0; qhead < todo.size(); qhead++) { + euf::enode_pair & pair = todo[qhead]; + euf::enode * r = pair.first; + euf::enode * sel = pair.second; + propagate_select_to_store_parents(r, sel, todo); + } + } + + void solver::propagate_select_to_store_parents(euf::enode* r, euf::enode* sel, euf::enode_pair_vector& todo) { + SASSERT(r->get_root() == r); + SASSERT(a.is_select(sel->get_expr())); + if (!ctx.is_relevant(r)) + return; + + for (euf::enode * parent : euf::enode_parents(r)) { + if (ctx.is_relevant(parent) && + a.is_store(parent->get_expr()) && + parent->get_arg(0)->get_root() == r) { + // propagate upward + select_set * parent_sel_set = get_select_set(parent); + euf::enode * parent_root = parent->get_root(); + + if (parent_sel_set->contains(sel)) + continue; + + SASSERT(sel->num_args() + 1 == parent->num_args()); + + // check whether the sel idx was overwritten by the store + unsigned num_args = sel->num_args(); + unsigned i = 1; + for (; i < num_args; i++) { + if (sel->get_arg(i)->get_root() != parent->get_arg(i)->get_root()) + break; + } + + if (i < num_args) { + SASSERT(!parent_sel_set->contains(sel) || (*(parent_sel_set->find(sel)))->get_root() == sel->get_root()); + parent_sel_set->insert(sel); + todo.push_back(std::make_pair(parent_root, sel)); + } + } + } + } + + solver::select_set* solver::get_select_set(euf::enode* n) { + euf::enode * r = n->get_root(); + select_set * set = nullptr; + m_selects.find(r, set); + if (set == nullptr) { + set = alloc(select_set); + m_selects.insert(r, set); + m_selects_domain.push_back(r); + m_selects_range.push_back(set); + } + return set; } void solver::collect_defaults() { diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 31bdba4a1..511f971a3 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -218,11 +218,39 @@ namespace array { void pop_core(unsigned n) override; // models + // I need a set of select enodes where select(A,i) = select(B,j) if i->get_root() == j->get_root() + struct sel_khasher { + unsigned operator()(euf::enode const * n) const { return 0; } + }; + + struct sel_chasher { + unsigned operator()(euf::enode const * n, unsigned idx) const { + return n->get_arg(idx+1)->get_root()->hash(); + } + }; + + struct sel_hash { + unsigned operator()(euf::enode * n) const; + }; + + struct sel_eq { + bool operator()(euf::enode * n1, euf::enode * n2) const; + }; + + typedef ptr_hashtable select_set; euf::enode_vector m_defaults; // temporary field for model construction ptr_vector m_else_values; // svector m_parents; // temporary field for model construction + obj_map m_selects; // mapping from array -> relevant selects + ptr_vector m_selects_domain; + ptr_vector m_selects_range; + bool must_have_different_model_values(theory_var v1, theory_var v2); + select_set* get_select_set(euf::enode* n); void collect_defaults(); + void collect_selects(); // mapping from array -> relevant selects + void propagate_select_to_store_parents(euf::enode* r, euf::enode* sel, euf::enode_pair_vector& todo); + void mg_merge(theory_var u, theory_var v); theory_var mg_find(theory_var n); void set_default(theory_var v, euf::enode* n); @@ -254,6 +282,7 @@ namespace array { void new_diseq_eh(euf::th_eq const& eq) override; bool unit_propagate() override; void init_model() override; + void finalize_model(model& mdl) override; bool include_func_interp(func_decl* f) const override { return a.is_ext(f); } void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override; bool add_dep(euf::enode* n, top_sort& dep) override; diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index b2d8d85b7..dbd042e98 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -188,6 +188,7 @@ namespace euf { enode* expr2enode(expr* e) const; enode* var2enode(theory_var v) const { return m_var2enode[v]; } expr* var2expr(theory_var v) const { return var2enode(v)->get_expr(); } + bool is_representative(theory_var v) const { return v == get_representative(v); } expr* bool_var2expr(sat::bool_var v) const; expr_ref literal2expr(sat::literal lit) const; enode* bool_var2enode(sat::bool_var v) const { expr* e = bool_var2expr(v); return e ? expr2enode(e) : nullptr; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 31acc2be0..6e1d77dd4 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -602,9 +602,11 @@ namespace smt { void add_row_entry(unsigned r_id, numeral const & coeff, theory_var v); uint_set& row_vars(); class scoped_row_vars; - + + void check_app(expr* e, expr* n); void internalize_internal_monomial(app * m, unsigned r_id); theory_var internalize_add(app * n); + theory_var internalize_sub(app * n); theory_var internalize_mul_core(app * m); theory_var internalize_mul(app * m); theory_var internalize_div(app * n); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 4a2963656..0168652cb 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -302,6 +302,44 @@ namespace smt { } } + template + void theory_arith::check_app(expr* e, expr* n) { + if (is_app(e)) + return; + std::ostringstream strm; + strm << mk_pp(n, m) << " contains a " << (is_var(e) ? "free variable":"quantifier"); + throw default_exception(strm.str()); + } + + + template + theory_var theory_arith::internalize_sub(app * n) { + VERIFY(m_util.is_sub(n)); + bool first = true; + unsigned r_id = mk_row(); + scoped_row_vars _sc(m_row_vars, m_row_vars_top); + theory_var v; + for (expr* arg : *n) { + check_app(arg, n); + v = internalize_term_core(to_app(arg)); + if (first) + add_row_entry(r_id, numeral::one(), v); + else + add_row_entry(r_id, numeral::one(), v); + first = false; + } + enode * e = mk_enode(n); + v = e->get_th_var(get_id()); + if (v == null_theory_var) { + v = mk_var(e); + add_row_entry(r_id, numeral::one(), v); + init_row(r_id); + } + else + del_row(r_id); + return v; + } + /** \brief Internalize a polynomial (+ h t). Return an alias for the monomial, that is, a variable v such that v = (+ h t) is a new row in the tableau. @@ -314,11 +352,7 @@ namespace smt { unsigned r_id = mk_row(); scoped_row_vars _sc(m_row_vars, m_row_vars_top); for (expr* arg : *n) { - if (is_var(arg)) { - std::ostringstream strm; - strm << mk_pp(n, m) << " contains a free variable"; - throw default_exception(strm.str()); - } + check_app(arg, n); internalize_internal_monomial(to_app(arg), r_id); } enode * e = mk_enode(n); @@ -383,11 +417,7 @@ namespace smt { } unsigned r_id = mk_row(); scoped_row_vars _sc(m_row_vars, m_row_vars_top); - if (is_var(arg1)) { - std::ostringstream strm; - strm << mk_pp(m, get_manager()) << " contains a free variable"; - throw default_exception(strm.str()); - } + check_app(arg1, m); if (reflection_enabled()) internalize_term_core(to_app(arg0)); theory_var v = internalize_mul_core(to_app(arg1)); @@ -749,7 +779,6 @@ namespace smt { return e->get_th_var(get_id()); } - SASSERT(!m_util.is_sub(n)); SASSERT(!m_util.is_uminus(n)); if (m_util.is_add(n)) @@ -770,6 +799,8 @@ namespace smt { return internalize_to_int(n); else if (m_util.is_numeral(n)) return internalize_numeral(n); + else if (m_util.is_sub(n)) + return internalize_sub(n); if (m_util.is_power(n)) { // unsupported found_unsupported_op(n); From c7922d69acd01895453f5efdc5baf84b2d735107 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Apr 2022 14:17:45 -0700 Subject: [PATCH 186/258] #5778 --- src/sat/sat_simplifier.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index a9910852e..5cb300725 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1806,6 +1806,8 @@ namespace sat { */ bool simplifier::resolve(clause_wrapper const & c1, clause_wrapper const & c2, literal l, literal_vector & r) { CTRACE("resolve_bug", !c1.contains(l), tout << c1 << "\n" << c2 << "\nl: " << l << "\n";); + if (m_visited.size() <= 2*s.num_vars()) + m_visited.resize(2*s.num_vars(), false); SASSERT(c1.contains(l)); SASSERT(c2.contains(~l)); bool res = true; @@ -1825,6 +1827,10 @@ namespace sat { literal l2 = c2[i]; if (not_l == l2) continue; + if ((~l2).index() >= m_visited.size()) { + s.display(std::cout << l2 << " " << s.num_vars() << " " << m_visited.size() << "\n"); + exit(0); + } if (m_visited[(~l2).index()]) { res = false; break; From 4cc33277fae793c07bec850faa2394aa9fbf8951 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Apr 2022 14:27:40 -0700 Subject: [PATCH 187/258] #5778 --- src/sat/smt/q_mam.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/q_mam.cpp b/src/sat/smt/q_mam.cpp index b029b0618..d860b3c3c 100644 --- a/src/sat/smt/q_mam.cpp +++ b/src/sat/smt/q_mam.cpp @@ -1893,7 +1893,8 @@ namespace q { } void recycle_enode_vector(enode_vector * v) { - m_pool.recycle(v); + if (v) + m_pool.recycle(v); } void update_max_generation(enode * n, enode * prev) { @@ -2197,8 +2198,10 @@ namespace q { if (curr->num_args() == expected_num_args && ctx.is_relevant(curr)) break; } - if (bp.m_it == bp.m_end) + if (bp.m_it == bp.m_end) { + recycle_enode_vector(bp.m_to_recycle); return nullptr; + } m_top++; update_max_generation(*(bp.m_it), nullptr); return *(bp.m_it); From 97115e5ebdcad46bd8cd9ce5fa208cfa645e4b04 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 00:14:59 -0700 Subject: [PATCH 188/258] #5778 add new clauses created during propagation to use-list --- src/sat/sat_simplifier.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 5cb300725..b3521452b 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -652,6 +652,7 @@ namespace sat { inline void simplifier::propagate_unit(literal l) { unsigned old_trail_sz = s.m_trail.size(); + unsigned num_clauses = s.m_clauses.size(); s.assign_scoped(l); s.propagate_core(false); // must not use propagate(), since s.m_clauses is not in a consistent state. if (s.inconsistent()) @@ -672,6 +673,8 @@ namespace sat { } cs.reset(); } + for (unsigned i = num_clauses; i < s.m_clauses.size(); ++i) + m_use_list.insert(*s.m_clauses[i]); } void simplifier::elim_lit(clause & c, literal l) { From 229ea569f1a8c5db6efff51e76b1ab75b8075d91 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 00:56:51 -0700 Subject: [PATCH 189/258] #5778 --- src/sat/smt/array_model.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index cb9ffe229..50b6ffd9e 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -31,11 +31,11 @@ namespace array { std::for_each(m_selects_range.begin(), m_selects_range.end(), delete_proc()); } - bool solver::add_dep(euf::enode* n, top_sort& dep) { + bool solver::add_dep(euf::enode* n, top_sort& dep) { if (!a.is_array(n->get_expr())) { dep.insert(n, nullptr); return true; - } + } for (euf::enode* p : euf::enode_parents(n->get_root())) { if (a.is_default(p->get_expr())) { dep.add(n, p); @@ -47,6 +47,13 @@ namespace array { for (unsigned i = 1; i < p->num_args(); ++i) dep.add(n, p->get_arg(i)); } + if (a.is_array(n->get_expr())) { + for (euf::enode* p : *get_select_set(n)) { + dep.add(n, p); + for (unsigned i = 1; i < p->num_args(); ++i) + dep.add(n, p->get_arg(i)); + } + } for (euf::enode* k : euf::enode_class(n)) if (a.is_const(k->get_expr())) dep.add(n, k->get_arg(0)); From 2fedcbd41e64335b0c690ecb2ac76bf8a3e591d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 01:27:56 -0700 Subject: [PATCH 190/258] #5778 --- src/sat/smt/euf_model.cpp | 10 +++++++++- src/sat/smt/euf_solver.h | 2 ++ src/sat/smt/q_mbi.cpp | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index fff7e5989..9f7f3b938 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -63,9 +63,17 @@ namespace euf { } }; + void solver::save_model(model_ref& mdl) { + m_qmodel = mdl; + } + void solver::update_model(model_ref& mdl) { TRACE("model", tout << "create model\n";); - mdl->reset_eval_cache(); + if (m_qmodel) { + mdl = m_qmodel; + return; + } + mdl->reset_eval_cache(); for (auto* mb : m_solvers) mb->init_model(); m_values.reset(); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 669eb1616..63439625b 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -154,6 +154,7 @@ namespace euf { // model building expr_ref_vector m_values; obj_map m_values2root; + model_ref m_qmodel; bool include_func_interp(func_decl* f); void register_macros(model& mdl); void dependencies2values(user_sort& us, deps_t& deps, model_ref& mdl); @@ -395,6 +396,7 @@ namespace euf { relevancy& get_relevancy() { return m_relevancy; } // model construction + void save_model(model_ref& mdl); void update_model(model_ref& mdl); obj_map const& values2root(); void model_updated(model_ref& mdl); diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index e7b7c2a01..af49f4eda 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -48,6 +48,7 @@ namespace q { lbool mbqi::operator()() { lbool result = l_true; m_model = nullptr; + ctx.save_model(m_model); m_instantiations.reset(); for (sat::literal lit : m_qs.m_universal) { quantifier* q = to_quantifier(ctx.bool_var2expr(lit.var())); @@ -73,6 +74,9 @@ namespace q { m_qs.add_clause(~qlit, ~lit); } m_instantiations.reset(); + if (result != l_true) + m_model = nullptr; + ctx.save_model(m_model); return result; } From ef28f0e2f0ab7cbdb5a0c3a5f40fb90f36ab047a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 01:28:58 -0700 Subject: [PATCH 191/258] #5778 deal with recursive calls to internalization with the same formula --- src/sat/tactic/goal2sat.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index faaee95f8..af07001e3 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -405,6 +405,8 @@ struct goal2sat::imp : public sat::sat_internalizer { m_result_stack.shrink(old_sz); } else { + if (process_cached(t, root, sign)) + return; SASSERT(num <= m_result_stack.size()); sat::bool_var k = add_var(false, t); sat::literal l(k, false); @@ -454,6 +456,8 @@ struct goal2sat::imp : public sat::sat_internalizer { m_result_stack.shrink(old_sz); } else { + if (process_cached(t, root, sign)) + return; SASSERT(num <= m_result_stack.size()); sat::bool_var k = add_var(false, t); sat::literal l(k, false); @@ -507,6 +511,8 @@ struct goal2sat::imp : public sat::sat_internalizer { } } else { + if (process_cached(n, root, sign)) + return; sat::bool_var k = add_var(false, n); sat::literal l(k, false); cache(n, l); @@ -537,6 +543,8 @@ struct goal2sat::imp : public sat::sat_internalizer { mk_root_clause(sign ? lit : ~lit); } else { + if (process_cached(t, root, sign)) + return; sat::bool_var k = add_var(false, t); sat::literal l(k, false); cache(t, l); @@ -567,6 +575,8 @@ struct goal2sat::imp : public sat::sat_internalizer { } } else { + if (process_cached(t, root, sign)) + return; sat::bool_var k = add_var(false, t); sat::literal l(k, false); cache(t, l); @@ -603,6 +613,8 @@ struct goal2sat::imp : public sat::sat_internalizer { } } else { + if (process_cached(t, root, sign)) + return; sat::bool_var k = add_var(false, t); sat::literal l(k, false); if (m.is_xor(t)) From 25feb0ebedbddb9c512d86243b292dfc02238af3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 17:43:12 -0700 Subject: [PATCH 192/258] #5938 catch also rewriter_exception that can be raised on cancelation and memory pressure --- src/tactic/arith/nla2bv_tactic.cpp | 2 +- src/tactic/tactical.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 887cc9e31..a73952be2 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -100,7 +100,7 @@ class nla2bv_tactic : public tactic { return; } substitute_vars(g); - TRACE("nla2bv", g.display(tout << "substitute vars\n");); + TRACE("nla2bv", g.display(tout << "substitute vars\n")); reduce_bv2int(g); reduce_bv2real(g); TRACE("nla2bv", g.display(tout << "after reduce\n");); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 2d14a5eaa..fa9382b8c 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -336,6 +336,9 @@ public: catch (tactic_exception &) { result.reset(); } + catch (rewriter_exception&) { + result.reset(); + } catch (z3_error & ex) { IF_VERBOSE(10, verbose_stream() << "z3 error: " << ex.error_code() << " in or-else\n"); throw; From d0ef5948aad0e98ce1f07ed750a83169924d173b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 17:49:03 -0700 Subject: [PATCH 193/258] nits --- src/tactic/arith/nla2bv_tactic.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index a73952be2..560b7b265 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -103,17 +103,16 @@ class nla2bv_tactic : public tactic { TRACE("nla2bv", g.display(tout << "substitute vars\n")); reduce_bv2int(g); reduce_bv2real(g); - TRACE("nla2bv", g.display(tout << "after reduce\n");); + TRACE("nla2bv", g.display(tout << "after reduce\n")); mc = m_fmc.get(); - for (unsigned i = 0; i < m_vars.size(); ++i) { - m_fmc->add(m_vars[i].get(), m_defs[i].get()); - } + for (unsigned i = 0; i < m_vars.size(); ++i) + m_fmc->add(m_vars.get(i), m_defs.get(i)); for (unsigned i = 0; i < m_bv2real.num_aux_decls(); ++i) { m_fmc->hide(m_bv2real.get_aux_decl(i)); } IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(nla->bv :sat-preserving " << m_is_sat_preserving << ")\n";); - TRACE("nla2bv_verbose", g.display(tout);); - TRACE("nla2bv", tout << "Muls: " << count_mul(g) << "\n";); + TRACE("nla2bv_verbose", g.display(tout)); + TRACE("nla2bv", tout << "Muls: " << count_mul(g) << "\n"); g.inc_depth(); if (!is_sat_preserving()) g.updt_prec(goal::UNDER); From 4b495e4b96ac65efe31e241efa8d1a4679a2d848 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 17:50:45 -0700 Subject: [PATCH 194/258] nits --- src/math/lp/lp_dual_simplex_def.h | 6 +++--- src/tactic/arith/bv2real_rewriter.cpp | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/math/lp/lp_dual_simplex_def.h b/src/math/lp/lp_dual_simplex_def.h index 34079cd94..c21429c88 100644 --- a/src/math/lp/lp_dual_simplex_def.h +++ b/src/math/lp/lp_dual_simplex_def.h @@ -217,14 +217,14 @@ template void lp_dual_simplex::fill_costs_bounds_ m_can_enter_basis[j] = true; this->set_scaled_cost(j); this->m_lower_bounds[j] = numeric_traits::zero(); - this->m_upper_bounds[j] =numeric_traits::one(); + this->m_upper_bounds[j] = numeric_traits::one(); break; } case column_type::free_column: { m_can_enter_basis[j] = true; this->set_scaled_cost(j); - this->m_upper_bounds[j] = free_bound; - this->m_lower_bounds[j] = -free_bound; + this->m_upper_bounds[j] = free_bound; + this->m_lower_bounds[j] = -free_bound; break; } case column_type::boxed: diff --git a/src/tactic/arith/bv2real_rewriter.cpp b/src/tactic/arith/bv2real_rewriter.cpp index bb8c17f33..d7bca705e 100644 --- a/src/tactic/arith/bv2real_rewriter.cpp +++ b/src/tactic/arith/bv2real_rewriter.cpp @@ -362,6 +362,11 @@ br_status bv2real_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * tout << mk_pp(args[i], m()) << " "; } tout << "\n";); + + if (u().memory_exceeded()) { + std::cout << "tactic exception\n"; + throw tactic_exception("bv2real-memory exceeded"); + } if(f->get_family_id() == m_arith.get_family_id()) { switch (f->get_decl_kind()) { case OP_NUM: return BR_FAILED; From 34272152bb11c2bdffe6e4d76bbfcf0985499161 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Apr 2022 17:52:54 -0700 Subject: [PATCH 195/258] add stubs to control memory usage --- src/tactic/arith/bv2real_rewriter.cpp | 12 ++++++++---- src/tactic/arith/bv2real_rewriter.h | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/tactic/arith/bv2real_rewriter.cpp b/src/tactic/arith/bv2real_rewriter.cpp index d7bca705e..03acc8161 100644 --- a/src/tactic/arith/bv2real_rewriter.cpp +++ b/src/tactic/arith/bv2real_rewriter.cpp @@ -17,6 +17,7 @@ Notes: --*/ #include "tactic/arith/bv2real_rewriter.h" +#include "tactic/tactic_exception.h" #include "ast/rewriter/rewriter_def.h" #include "ast/ast_pp.h" #include "ast/for_each_expr.h" @@ -40,6 +41,7 @@ bv2real_util::bv2real_util(ast_manager& m, rational const& default_root, rationa m_pos_le = m.mk_fresh_func_decl("<=","",2,domain,m.mk_bool_sort()); m_decls.push_back(m_pos_lt); m_decls.push_back(m_pos_le); + m_max_memory = std::max((1ull << 31ull), 3*memory::get_allocation_size()); } bool bv2real_util::is_bv2real(func_decl* f) const { @@ -178,12 +180,10 @@ void bv2real_util::align_divisors(expr_ref& s1, expr_ref& s2, expr_ref& t1, expr expr* bv2real_util::mk_bv_mul(expr* s, expr* t) { SASSERT(m_bv.is_bv(s)); SASSERT(m_bv.is_bv(t)); - if (is_zero(s)) { + if (is_zero(s)) return s; - } - if (is_zero(t)) { + if (is_zero(t)) return t; - } expr_ref s1(s, m()), t1(t, m()); align_sizes(s1, t1); unsigned n = m_bv.get_bv_size(t1); @@ -343,6 +343,10 @@ bool bv2real_util::mk_is_divisible_by(expr_ref& s, rational const& _overflow) { } +bool bv2real_util::memory_exceeded() const { + return m_max_memory <= memory::get_allocation_size(); +} + // --------------------------------------------------------------------- // bv2real_rewriter diff --git a/src/tactic/arith/bv2real_rewriter.h b/src/tactic/arith/bv2real_rewriter.h index 7b3915105..4c3c63c2a 100644 --- a/src/tactic/arith/bv2real_rewriter.h +++ b/src/tactic/arith/bv2real_rewriter.h @@ -65,6 +65,7 @@ class bv2real_util { rational m_default_divisor; rational m_max_divisor; unsigned m_max_num_bits; + uint64_t m_max_memory; class contains_bv2real_proc; @@ -81,6 +82,8 @@ public: bool contains_bv2real(expr* e) const; + bool memory_exceeded() const; + bool mk_bv2real(expr* s, expr* t, rational& d, rational& r, expr_ref& result); expr* mk_bv2real_c(expr* s, expr* t, rational const& d, rational const& r); expr* mk_bv2real(expr* n, expr* m) { return mk_bv2real_c(n, m, default_divisor(), default_root()); } From 46cc54fbabb3e44dce8da329270d7109ba90d1e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Apr 2022 07:55:51 -0700 Subject: [PATCH 196/258] outdated warning --- src/tactic/tactical.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index fa9382b8c..9167650ad 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -1022,7 +1022,6 @@ public: void operator()(goal_ref const & in, goal_ref_buffer& result) override { cancel_eh eh(in->m().limit()); { - // Warning: scoped_timer is not thread safe in Linux. scoped_timer timer(m_timeout, &eh); m_t->operator()(in, result); } From 03a2d9a0183982b8ad412f94640c736a800a59e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Apr 2022 11:03:28 -0700 Subject: [PATCH 197/258] fix #5942 --- src/smt/theory_seq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 330a608a4..d09069ce4 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1498,8 +1498,8 @@ void theory_seq::add_length(expr* l) { TRACE("seq", tout << mk_bounded_pp(e, m, 2) << "\n";); m_length.push_back(l); m_has_length.insert(e); - m_trail_stack.push(insert_obj_trail(m_has_length, e)); m_trail_stack.push(push_back_vector(m_length)); + m_trail_stack.push(insert_obj_trail(m_has_length, e)); } /** From 321745fdb1915a9f0995d0587da441363bcbe03f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Apr 2022 11:07:54 -0700 Subject: [PATCH 198/258] #5941 Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1fca64f29..7cc83f890 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2550,7 +2550,7 @@ def mk_config(): if GIT_HASH: CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH) CXXFLAGS = '%s -std=c++17' % CXXFLAGS - CXXFLAGS = '%s -fvisibility=hidden -fvisibility-inlines-hidden -c' % CXXFLAGS + CXXFLAGS = '%s -fvisibility=protected -fvisibility-inlines-hidden -c' % CXXFLAGS FPMATH = test_fpmath(CXX) CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS) if LOG_SYNC: From 05ec77cb56b56bec3bc5edcba2b38f1a3dfc9675 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Apr 2022 12:20:10 -0700 Subject: [PATCH 199/258] revert --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 7cc83f890..1fca64f29 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2550,7 +2550,7 @@ def mk_config(): if GIT_HASH: CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH) CXXFLAGS = '%s -std=c++17' % CXXFLAGS - CXXFLAGS = '%s -fvisibility=protected -fvisibility-inlines-hidden -c' % CXXFLAGS + CXXFLAGS = '%s -fvisibility=hidden -fvisibility-inlines-hidden -c' % CXXFLAGS FPMATH = test_fpmath(CXX) CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS) if LOG_SYNC: From 4f6811a6a26b071a0b8dd906fa4fef4b7ebebdae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Apr 2022 21:10:53 -0700 Subject: [PATCH 200/258] with simplification --- examples/python/efsmt.py | 52 ++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/examples/python/efsmt.py b/examples/python/efsmt.py index 53c83c02e..afd9a21ae 100644 --- a/examples/python/efsmt.py +++ b/examples/python/efsmt.py @@ -5,43 +5,33 @@ from z3.z3util import get_vars Modified from the example in pysmt https://github.com/pysmt/pysmt/blob/97088bf3b0d64137c3099ef79a4e153b10ccfda7/examples/efsmt.py ''' -def efsmt(y, phi, maxloops=None): - """Solving exists x. forall y. phi(x, y)""" - vars = get_vars(phi) - x = [item for item in vars if item not in y] - esolver = Solver() - fsolver = Solver() - esolver.add(BoolVal(True)) + +def efsmt(ys, phi, maxloops = None): + """Solving exists xs. forall ys. phi(x, y)""" + xs = [x for x in get_vars(phi) if x not in ys] + E = Solver() + F = Solver() + E.add(BoolVal(True)) loops = 0 while maxloops is None or loops <= maxloops: loops += 1 - eres = esolver.check() + eres = E.check() if eres == unsat: return unsat else: - emodel = esolver.model() - tau = [emodel.eval(var, True) for var in x] - sub_phi = phi - for i in range(len(x)): - sub_phi = simplify(substitute(sub_phi, (x[i], tau[i]))) - fsolver.add(Not(sub_phi)) - if fsolver.check() == sat: - fmodel = fsolver.model() - sigma = [fmodel.eval(v, True) for v in y] - sub_phi = phi - for j in range(len(y)): - sub_phi = simplify(substitute(sub_phi, (y[j], sigma[j]))) - esolver.add(sub_phi) + emodel = E.model() + sub_phi = substitute(phi, [(x, emodel.eval(x, True)) for x in xs]) + F.push() + F.add(Not(sub_phi)) + if F.check() == sat: + fmodel = F.model() + sub_phi = substitute(phi, [(y, fmodel.eval(y, True)) for y in ys]) + E.add(sub_phi) else: - return sat + return sat, [(x, emodel.eval(x, True)) for x in xs] + F.pop() return unknown - -def test(): - x, y, z = Reals("x y z") - fmla = Implies(And(y > 0, y < 10), y - 2 * x < 7) - fmlb = And(y > 3, x == 1) - print(efsmt([y], fmla)) - print(efsmt([y], fmlb)) - -test() +x, y, z = Reals("x y z") +print(efsmt([y], Implies(And(y > 0, y < 10), y - 2 * x < 7))) +print(efsmt([y], And(y > 3, x == 1))) From 053cb72cc2b470895524b4ba5ca5ec95ea0e472e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Apr 2022 20:19:15 +0200 Subject: [PATCH 201/258] handle return status --- examples/python/efsmt.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/python/efsmt.py b/examples/python/efsmt.py index afd9a21ae..e519ed8c0 100644 --- a/examples/python/efsmt.py +++ b/examples/python/efsmt.py @@ -16,20 +16,21 @@ def efsmt(ys, phi, maxloops = None): while maxloops is None or loops <= maxloops: loops += 1 eres = E.check() - if eres == unsat: - return unsat - else: + if eres == sat: emodel = E.model() sub_phi = substitute(phi, [(x, emodel.eval(x, True)) for x in xs]) F.push() F.add(Not(sub_phi)) - if F.check() == sat: + fres = F.check() + if fres == sat: fmodel = F.model() sub_phi = substitute(phi, [(y, fmodel.eval(y, True)) for y in ys]) E.add(sub_phi) else: - return sat, [(x, emodel.eval(x, True)) for x in xs] + return fres, [(x, emodel.eval(x, True)) for x in xs] F.pop() + else: + return eres return unknown x, y, z = Reals("x y z") From a5d588ce0979c5a60b716e88e87249a65beb5074 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Apr 2022 04:26:40 +0200 Subject: [PATCH 202/258] add example for #5933 --- examples/python/visitor.py | 76 +++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/examples/python/visitor.py b/examples/python/visitor.py index 504e2acc8..78ec824fb 100644 --- a/examples/python/visitor.py +++ b/examples/python/visitor.py @@ -17,13 +17,71 @@ def visitor(e, seen): yield e return -x, y = Ints('x y') -fml = x + x + y > 2 -seen = {} -for e in visitor(fml, seen): - if is_const(e) and e.decl().kind() == Z3_OP_UNINTERPRETED: - print("Variable", e) - else: - print(e) - +def modify(e, fn): + seen = {} + def visit(e): + if e in seen: + pass + elif fn(e) is not None: + seen[e] = fn(e) + elif is_and(e): + chs = [visit(ch) for ch in e.children()] + seen[e] = And(chs) + elif is_or(e): + chs = [visit(ch) for ch in e.children()] + seen[e] = Or(chs) + elif is_app(e): + chs = [visit(ch) for ch in e.children()] + seen[e] = e.decl()(chs) + elif is_quantifier(e): + # Note: does not work for Lambda that requires a separate case + body = visit(e.body()) + is_forall = e.is_forall() + num_pats = e.num_patterns() + pats = (Pattern * num_pats)() + for i in range(num_pats): + pats[i] = e.pattern(i).ast + + num_decls = e.num_vars() + sorts = (Sort * num_decls)() + names = (Symbol * num_decls)() + for i in range(num_decls): + sorts[i] = e.var_sort(i).ast + names[i] = to_symbol(e.var_name(i), e.ctx) + r = QuantifierRef(Z3_mk_quantifier(e.ctx_ref(), is_forall, e.weight(), num_pats, pats, num_decls, sorts, names, body.ast), e.ctx) + seen[e] = r + else: + seen[e] = e + return seen[e] + return visit(e) + +if __name__ == "__main__": + x, y = Ints('x y') + fml = x + x + y > 2 + seen = {} + for e in visitor(fml, seen): + if is_const(e) and e.decl().kind() == Z3_OP_UNINTERPRETED: + print("Variable", e) + else: + print(e) + + s = SolverFor("HORN") + inv = Function('inv', IntSort(), IntSort(), BoolSort()) + i, ip, j, jp = Ints('i ip j jp') + s.add(ForAll([i, j], Implies(i == 0, inv(i, j)))) + s.add(ForAll([i, ip, j, jp], Implies(And(inv(i, j), i < 10, ip == i + 1), inv(ip, jp)))) + s.add(ForAll([i, j], Implies(And(inv(i, j), i >= 10), i == 10))) + + a0, a1, a2 = Ints('a0 a1 a2') + b0, b1, b2 = Ints('b0 b1 b2') + x = Var(0, IntSort()) + y = Var(1, IntSort()) + template = And(a0 + a1*x + a2*y >= 0, b0 + b1*x + b2*y >= 0) + def update(e): + if is_app(e) and eq(e.decl(), inv): + return substitute_vars(template, (e.arg(0)), e.arg(1)) + return None + for f in s.assertions(): + f_new = modify(f, update) + print(f_new) From bd70c79b255d2c0e43bea6cb256a9251b9b9f5ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Apr 2022 15:53:53 +0200 Subject: [PATCH 203/258] Update target_arch_detect.cpp adding detection for ARM to cmake build --- cmake/target_arch_detect.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/target_arch_detect.cpp b/cmake/target_arch_detect.cpp index 8053e3532..0a2d0f3e6 100644 --- a/cmake/target_arch_detect.cpp +++ b/cmake/target_arch_detect.cpp @@ -5,6 +5,8 @@ #error CMAKE_TARGET_ARCH_i686 #elif defined(__x86_64__) || defined(_M_X64) #error CMAKE_TARGET_ARCH_x86_64 +#elif defined(__ARM_ARCH) +#error CMAKE_TARGET_ARCH_arm #else #error CMAKE_TARGET_ARCH_unknown #endif From ac2523af82c96c7a767a8d4c36432dd38522284a Mon Sep 17 00:00:00 2001 From: fleisherdev <55119509+fleisherdev@users.noreply.github.com> Date: Tue, 5 Apr 2022 23:37:51 -0400 Subject: [PATCH 204/258] Fix null ref on access of Entry[] contents (#5947) Co-authored-by: jfleisher --- src/api/dotnet/NativeFuncInterp.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/NativeFuncInterp.cs b/src/api/dotnet/NativeFuncInterp.cs index 86bb27c55..0f446fa6f 100644 --- a/src/api/dotnet/NativeFuncInterp.cs +++ b/src/api/dotnet/NativeFuncInterp.cs @@ -85,13 +85,14 @@ namespace Microsoft.Z3 for (uint j = 0; j < numEntries; ++j) { - var entry = Native.Z3_func_interp_get_entry(nCtx, fi, j); - Native.Z3_func_entry_inc_ref(nCtx, entry); + var ntvEntry = Native.Z3_func_interp_get_entry(nCtx, fi, j); + Entries[j] = new Entry(); + Native.Z3_func_entry_inc_ref(nCtx, ntvEntry); Entries[j].Arguments = new Z3_ast[numArgs]; for (uint i = 0; i < numArgs; ++i) - Entries[j].Arguments[i] = Native.Z3_func_entry_get_arg(nCtx, entry, i); - Entries[j].Result = Native.Z3_func_entry_get_value(nCtx, entry); - Native.Z3_func_entry_dec_ref(nCtx, entry); + Entries[j].Arguments[i] = Native.Z3_func_entry_get_arg(nCtx, ntvEntry, i); + Entries[j].Result = Native.Z3_func_entry_get_value(nCtx, ntvEntry); + Native.Z3_func_entry_dec_ref(nCtx, ntvEntry); } Native.Z3_func_interp_dec_ref(nCtx, fi); From cebbc7133077bcbcc3e10e94851c1b6ced43c2a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Apr 2022 07:58:19 +0200 Subject: [PATCH 205/258] #5778 ensure else value so that defaults align across equivalence class --- src/sat/smt/array_model.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index 50b6ffd9e..5b1042db0 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -116,6 +116,12 @@ namespace array { if (!get_else(v) && fi->get_else()) set_else(v, fi->get_else()); + if (!get_else(v)) { + expr* else_value = mdl.get_some_value(get_array_range(srt)); + fi->set_else(else_value); + set_else(v, else_value); + } + for (euf::enode* p : *get_select_set(n)) { expr* value = values.get(p->get_root_id(), nullptr); if (!value || value == fi->get_else()) From 2f63747c7b8786b2a8ddf255221074fb7a71d62b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Apr 2022 08:17:27 +0200 Subject: [PATCH 206/258] #5778 Signed-off-by: Nikolaj Bjorner --- src/sat/smt/array_model.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index 5b1042db0..b295ce282 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -36,19 +36,13 @@ namespace array { dep.insert(n, nullptr); return true; } - for (euf::enode* p : euf::enode_parents(n->get_root())) { - if (a.is_default(p->get_expr())) { - dep.add(n, p); - continue; - } - if (!a.is_select(p->get_expr())) - continue; - dep.add(n, p); - for (unsigned i = 1; i < p->num_args(); ++i) - dep.add(n, p->get_arg(i)); - } if (a.is_array(n->get_expr())) { + for (euf::enode* p : euf::enode_parents(n->get_root())) + if (a.is_default(p->get_expr())) + dep.add(n, p); + for (euf::enode* p : *get_select_set(n)) { + SASSERT(n != p); dep.add(n, p); for (unsigned i = 1; i < p->num_args(); ++i) dep.add(n, p->get_arg(i)); @@ -56,11 +50,16 @@ namespace array { } for (euf::enode* k : euf::enode_class(n)) if (a.is_const(k->get_expr())) - dep.add(n, k->get_arg(0)); + dep.add(n, k->get_arg(0)); + for (euf::enode* k : euf::enode_class(n)) + if (a.is_const(k->get_expr())) { + SASSERT(n != k->get_arg(0)); + } theory_var v = get_th_var(n); euf::enode* d = get_default(v); if (d) dep.add(n, d); + SASSERT(n != d); if (!dep.deps().contains(n)) dep.insert(n, nullptr); return true; @@ -127,6 +126,12 @@ namespace array { if (!value || value == fi->get_else()) continue; args.reset(); + for (unsigned i = 1; i < p->num_args(); ++i) { + if (!values.get(p->get_arg(i)->get_root_id())) { + TRACE("array", tout << ctx.bpp(p->get_arg(i)) << "\n"); + } + SASSERT(values.get(p->get_arg(i)->get_root_id())); + } for (unsigned i = 1; i < p->num_args(); ++i) args.push_back(values.get(p->get_arg(i)->get_root_id())); fi->insert_entry(args.data(), value); From b0dce5b27d063e954ef0ea506c4600a5ddcb6d25 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Apr 2022 08:53:12 +0200 Subject: [PATCH 207/258] remove debug asserts --- src/sat/smt/array_model.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index b295ce282..c437629f5 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -42,7 +42,6 @@ namespace array { dep.add(n, p); for (euf::enode* p : *get_select_set(n)) { - SASSERT(n != p); dep.add(n, p); for (unsigned i = 1; i < p->num_args(); ++i) dep.add(n, p->get_arg(i)); @@ -51,15 +50,10 @@ namespace array { for (euf::enode* k : euf::enode_class(n)) if (a.is_const(k->get_expr())) dep.add(n, k->get_arg(0)); - for (euf::enode* k : euf::enode_class(n)) - if (a.is_const(k->get_expr())) { - SASSERT(n != k->get_arg(0)); - } theory_var v = get_th_var(n); euf::enode* d = get_default(v); if (d) dep.add(n, d); - SASSERT(n != d); if (!dep.deps().contains(n)) dep.insert(n, nullptr); return true; From 0fa0feb97930a72b550bf0032e57a0ec8d3df63c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Apr 2022 16:27:10 +0200 Subject: [PATCH 208/258] allow add_expr during pop Signed-off-by: Nikolaj Bjorner --- src/smt/theory_user_propagator.cpp | 36 +++++++++++++++++++++++------- src/smt/theory_user_propagator.h | 4 ++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 08170d4eb..7c53aa8eb 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -24,7 +24,8 @@ using namespace smt; theory_user_propagator::theory_user_propagator(context& ctx): theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name())), - m_var2expr(ctx.get_manager()) + m_var2expr(ctx.get_manager()), + m_to_add(ctx.get_manager()) {} theory_user_propagator::~theory_user_propagator() { @@ -33,9 +34,11 @@ theory_user_propagator::~theory_user_propagator() { void theory_user_propagator::force_push() { for (; m_num_scopes > 0; --m_num_scopes) { + flet _pushing(m_push_popping, true); theory::push_scope_eh(); - m_push_eh(m_user_context); m_prop_lim.push_back(m_prop.size()); + m_to_add_lim.push_back(m_to_add.size()); + m_push_eh(m_user_context); } } @@ -82,6 +85,7 @@ void theory_user_propagator::propagate_cb( expr* conseq) { CTRACE("user_propagate", ctx.lit_internalized(conseq) && ctx.get_assignment(ctx.get_literal(conseq)) == l_true, ctx.display(tout << "redundant consequence: " << mk_pp(conseq, m) << "\n")); + expr_ref _conseq(conseq, m); ctx.get_rewriter()(conseq, _conseq); if (ctx.lit_internalized(_conseq) && ctx.get_assignment(ctx.get_literal(_conseq)) == l_true) @@ -90,7 +94,10 @@ void theory_user_propagator::propagate_cb( } void theory_user_propagator::register_cb(expr* e) { - add_expr(e, true); + if (m_push_popping) + m_to_add.push_back(e); + else + add_expr(e, true); } theory * theory_user_propagator::mk_fresh(context * new_ctx) { @@ -144,25 +151,29 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu } } -void theory_user_propagator::push_scope_eh() { +void theory_user_propagator::push_scope_eh() { ++m_num_scopes; } void theory_user_propagator::pop_scope_eh(unsigned num_scopes) { + flet _popping(m_push_popping, true); unsigned n = std::min(num_scopes, m_num_scopes); m_num_scopes -= n; num_scopes -= n; if (num_scopes == 0) return; - m_pop_eh(m_user_context, num_scopes); theory::pop_scope_eh(num_scopes); unsigned old_sz = m_prop_lim.size() - num_scopes; m_prop.shrink(m_prop_lim[old_sz]); m_prop_lim.shrink(old_sz); + old_sz = m_to_add_lim.size() - num_scopes; + m_to_add.shrink(m_to_add_lim[old_sz]); + m_to_add_lim.shrink(old_sz); + m_pop_eh(m_user_context, num_scopes); } bool theory_user_propagator::can_propagate() { - return m_qhead < m_prop.size(); + return m_qhead < m_prop.size() || !m_to_add.empty(); } void theory_user_propagator::propagate_consequence(prop_info const& prop) { @@ -215,10 +226,19 @@ void theory_user_propagator::propagate_new_fixed(prop_info const& prop) { void theory_user_propagator::propagate() { TRACE("user_propagate", tout << "propagating queue head: " << m_qhead << " prop queue: " << m_prop.size() << "\n"); - if (m_qhead == m_prop.size()) + if (m_qhead == m_prop.size() && m_to_add_qhead == m_to_add.size()) return; force_push(); - unsigned qhead = m_qhead; + + unsigned qhead = m_to_add_qhead; + if (qhead < m_to_add.size()) { + for (; qhead < m_to_add.size(); ++qhead) + add_expr(m_to_add.get(qhead), true); + ctx.push_trail(value_trail(m_to_add_qhead)); + m_to_add_qhead = qhead; + } + + qhead = m_qhead; while (qhead < m_prop.size() && !ctx.inconsistent()) { auto const& prop = m_prop[qhead]; if (prop.m_var == null_theory_var) diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index d3194a3fe..9b271e9c3 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -78,6 +78,10 @@ namespace smt { stats m_stats; expr_ref_vector m_var2expr; unsigned_vector m_expr2var; + bool m_push_popping; + expr_ref_vector m_to_add; + unsigned_vector m_to_add_lim; + unsigned m_to_add_qhead = 0; expr* var2expr(theory_var v) { return m_var2expr.get(v); } theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; } From a863a91b130bd0e2a7af2f4ce9f7943df71555a8 Mon Sep 17 00:00:00 2001 From: fleisherdev <55119509+fleisherdev@users.noreply.github.com> Date: Thu, 7 Apr 2022 02:19:21 -0400 Subject: [PATCH 209/258] Allow nightly builds to complete even if package signing fails - NOT published to nuget.org (#5951) Co-authored-by: jofleish --- scripts/nightly.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 374249432..e81135ab5 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -194,6 +194,7 @@ stages: patchVersion: $(Patch) arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' @@ -221,6 +222,7 @@ stages: MaxConcurrency: '50' MaxRetryAttempts: '5' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Symbol Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' @@ -297,6 +299,7 @@ stages: patchVersion: $(Patch) arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' @@ -324,6 +327,7 @@ stages: MaxConcurrency: '50' MaxRetryAttempts: '5' - task: EsrpCodeSigning@1 + continueOnError: true displayName: 'Sign Symbol Package' inputs: ConnectedServiceName: 'z3-esrp-signing-2' From 19531654227522416cd37d48e7407d1ae055ec4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Apr 2022 08:35:45 +0200 Subject: [PATCH 210/258] set ARM64 if detected under OSX --- CMakeLists.txt | 4 +++- cmake/target_arch_detect.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9e121d02..5fef02be9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,7 +198,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "GNU") message(STATUS "Platform: GNU/Hurd") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_HURD_") elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - # Does macOS really not need any special flags? + if (TARGET_ARCHITECTURE STREQUAL "arm64") + set(CMAKE_OSX_ARCHITECTURES "arm64") + endif() message(STATUS "Platform: Darwin") elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") message(STATUS "Platform: FreeBSD") diff --git a/cmake/target_arch_detect.cpp b/cmake/target_arch_detect.cpp index 0a2d0f3e6..379b5817e 100644 --- a/cmake/target_arch_detect.cpp +++ b/cmake/target_arch_detect.cpp @@ -5,6 +5,8 @@ #error CMAKE_TARGET_ARCH_i686 #elif defined(__x86_64__) || defined(_M_X64) #error CMAKE_TARGET_ARCH_x86_64 +#elif defined(__ARM_ARCH_ISA_A64) +#error CMAKE_TARGET_ARCH_arm64 #elif defined(__ARM_ARCH) #error CMAKE_TARGET_ARCH_arm #else From 8c2909f52bda61ce2422f6fb6484fa69a651e59d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Apr 2022 13:36:23 +0200 Subject: [PATCH 211/258] working on python make for arm Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 ++++ src/ast/pb_decl_plugin.cpp | 10 +++++----- src/ast/special_relations_decl_plugin.cpp | 10 +++++----- src/util/params.cpp | 17 +++++++++-------- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1fca64f29..78c983ec4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -69,6 +69,7 @@ IS_WINDOWS=False IS_LINUX=False IS_HURD=False IS_OSX=False +IS_OS_ARM64=False IS_FREEBSD=False IS_NETBSD=False IS_OPENBSD=False @@ -598,6 +599,9 @@ if os.name == 'nt': elif os.name == 'posix': if os.uname()[0] == 'Darwin': IS_OSX=True + print("setting Darwin", os.uname()[4]) + if os.uname()[4] == 'arm64': + IS_OS_ARM64 = True elif os.uname()[0] == 'Linux': IS_LINUX=True elif os.uname()[0] == 'GNU': diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index d4797b507..10e6c694c 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -90,11 +90,11 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p void pb_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null || logic == "QF_FD" || logic == "ALL" || logic == "HORN") { - op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K)); - op_names.push_back(builtin_name(m_at_least_sym.bare_str(), OP_AT_LEAST_K)); - op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); - op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE)); - op_names.push_back(builtin_name(m_pbeq_sym.bare_str(), OP_PB_EQ)); + op_names.push_back(builtin_name(m_at_most_sym.str(), OP_AT_MOST_K)); + op_names.push_back(builtin_name(m_at_least_sym.str(), OP_AT_LEAST_K)); + op_names.push_back(builtin_name(m_pble_sym.str(), OP_PB_LE)); + op_names.push_back(builtin_name(m_pbge_sym.str(), OP_PB_GE)); + op_names.push_back(builtin_name(m_pbeq_sym.str(), OP_PB_EQ)); } } diff --git a/src/ast/special_relations_decl_plugin.cpp b/src/ast/special_relations_decl_plugin.cpp index 5dc5f32fe..7ed5e8346 100644 --- a/src/ast/special_relations_decl_plugin.cpp +++ b/src/ast/special_relations_decl_plugin.cpp @@ -61,11 +61,11 @@ func_decl * special_relations_decl_plugin::mk_func_decl( void special_relations_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null) { - op_names.push_back(builtin_name(m_po.bare_str(), OP_SPECIAL_RELATION_PO)); - op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO)); - op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO)); - op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO)); - op_names.push_back(builtin_name(m_tc.bare_str(), OP_SPECIAL_RELATION_TC)); + op_names.push_back(builtin_name(m_po.str(), OP_SPECIAL_RELATION_PO)); + op_names.push_back(builtin_name(m_lo.str(), OP_SPECIAL_RELATION_LO)); + op_names.push_back(builtin_name(m_plo.str(), OP_SPECIAL_RELATION_PLO)); + op_names.push_back(builtin_name(m_to.str(), OP_SPECIAL_RELATION_TO)); + op_names.push_back(builtin_name(m_tc.str(), OP_SPECIAL_RELATION_TC)); } } diff --git a/src/util/params.cpp b/src/util/params.cpp index aefe4e074..1745e56fd 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -24,15 +24,14 @@ Notes: params_ref params_ref::g_empty_params_ref; -std::string norm_param_name(char const * n) { - if (n == nullptr) - return "_"; +std::string norm_param_name(char const* n) { if (*n == ':') n++; std::string r = n; unsigned sz = static_cast(r.size()); if (sz == 0) return "_"; + for (unsigned i = 0; i < sz; i++) { char curr = r[i]; if ('A' <= curr && curr <= 'Z') @@ -44,6 +43,8 @@ std::string norm_param_name(char const * n) { } std::string norm_param_name(symbol const & n) { + if (n.is_null()) + return "_"; return norm_param_name(n.bare_str()); } @@ -156,8 +157,8 @@ struct param_descrs::imp { return m_names[idx]; } - struct lt { - bool operator()(symbol const & s1, symbol const & s2) const { return strcmp(s1.bare_str(), s2.bare_str()) < 0; } + struct symlt { + bool operator()(symbol const & s1, symbol const & s2) const { return ::lt(s1, s2); } }; void display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) const { @@ -165,13 +166,13 @@ struct param_descrs::imp { for (auto const& kv : m_info) { names.push_back(kv.m_key); } - std::sort(names.begin(), names.end(), lt()); + std::sort(names.begin(), names.end(), symlt()); for (symbol const& name : names) { for (unsigned i = 0; i < indent; i++) out << " "; if (smt2_style) out << ':'; - char const * s = name.bare_str(); - unsigned n = static_cast(strlen(s)); + std::string s = name.str(); + unsigned n = static_cast(s.length()); for (unsigned i = 0; i < n; i++) { if (smt2_style && s[i] == '_') out << '-'; From c47bd1d01f8abdd4937f761e0d32e46c61d46d7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Apr 2022 13:43:35 +0200 Subject: [PATCH 212/258] add arm64 auto-detect Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 78c983ec4..e25d90433 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -599,7 +599,6 @@ if os.name == 'nt': elif os.name == 'posix': if os.uname()[0] == 'Darwin': IS_OSX=True - print("setting Darwin", os.uname()[4]) if os.uname()[4] == 'arm64': IS_OS_ARM64 = True elif os.uname()[0] == 'Linux': @@ -2640,6 +2639,10 @@ def mk_config(): LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): CXXFLAGS = '%s -fpic' % CXXFLAGS + if IS_OSX and IS_OS_ARM64: + CXXFLAGS = '%s -arch arm64' % CXXFLAGS + LDFLAGS = '%s -arch arm64' % LDFLAGS + SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS config.write('PREFIX=%s\n' % PREFIX) config.write('CC=%s\n' % CC) From 2e91d6688883552f635c53f0d30469ec65b8f00c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 06:28:36 +0200 Subject: [PATCH 213/258] Update mk_util.py use more meaningful name --- scripts/mk_util.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index e25d90433..6575f0dbf 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -69,7 +69,7 @@ IS_WINDOWS=False IS_LINUX=False IS_HURD=False IS_OSX=False -IS_OS_ARM64=False +IS_ARCH_ARM64=False IS_FREEBSD=False IS_NETBSD=False IS_OPENBSD=False @@ -599,8 +599,6 @@ if os.name == 'nt': elif os.name == 'posix': if os.uname()[0] == 'Darwin': IS_OSX=True - if os.uname()[4] == 'arm64': - IS_OS_ARM64 = True elif os.uname()[0] == 'Linux': IS_LINUX=True elif os.uname()[0] == 'GNU': @@ -624,7 +622,10 @@ elif os.name == 'posix': else: LINUX_X64=False +if os.uname()[4] == 'arm64': + IS_ARCH_ARM64 = True + def display_help(exit_code): print("mk_make.py: Z3 Makefile generator\n") print("This script generates the Makefile for the Z3 theorem prover.") @@ -2639,7 +2640,7 @@ def mk_config(): LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): CXXFLAGS = '%s -fpic' % CXXFLAGS - if IS_OSX and IS_OS_ARM64: + if IS_OSX and IS_ARCH_ARM64: CXXFLAGS = '%s -arch arm64' % CXXFLAGS LDFLAGS = '%s -arch arm64' % LDFLAGS SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS From 83d2aa85ec7276a53b8978756bc94e7214b5097d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 06:35:25 +0200 Subject: [PATCH 214/258] add arm64 build path --- scripts/mk_unix_dist.py | 6 ++++++ scripts/nightly.yaml | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 28d68a01b..f5cbf6504 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -72,6 +72,7 @@ def parse_options(): 'nojava', 'nodotnet', 'dotnet-key=', + 'arch=', 'githash', 'nopython' ]) @@ -96,6 +97,11 @@ def parse_options(): JAVA_ENABLED = False elif opt == '--githash': GIT_HASH = True + elif opt == '--arch': + if arg == "arm64": + mk_util.IS_ARCH_ARM64 = True + else: + raise MKException(f"Invalid architecture directive '{arg}'. Legal directives: arm64") else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e81135ab5..4296cab08 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -4,7 +4,6 @@ variables: Minor: '8' Patch: '16' NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName) - MacFlags: 'CXXFLAGS="-arch x86_64" LINK_EXTRA_FLAGS="-arch x86_64" SLINK_EXTRA_FLAGS="-arch x86_64"' stages: - stage: Build @@ -15,7 +14,7 @@ stages: pool: vmImage: "macOS-latest" steps: - - script: $(MacFlags) python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - script: git clone https://github.com/z3prover/z3test z3test - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. @@ -25,6 +24,21 @@ stages: targetPath: $(Build.ArtifactStagingDirectory) + - job: MacArm64 + displayName: "Mac ARM64 Build" + pool: + vmImage: "macOS-latest" + steps: + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 + - script: git clone https://github.com/z3prover/z3test z3test + - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 + - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. + - task: PublishPipelineArtifact@1 + inputs: + artifactName: 'MacArm64' + targetPath: $(Build.ArtifactStagingDirectory) + + - job: Ubuntu displayName: "Ubuntu build" pool: From babac78c999437ce7fe5c5c9e9e3eab45ded95b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 06:59:07 +0200 Subject: [PATCH 215/258] syntax error? --- scripts/mk_unix_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index f5cbf6504..39f48f448 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -101,7 +101,7 @@ def parse_options(): if arg == "arm64": mk_util.IS_ARCH_ARM64 = True else: - raise MKException(f"Invalid architecture directive '{arg}'. Legal directives: arm64") + raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg) else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) From 1346a168a1346405a313c2a9eceb2560576f8e02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 07:00:53 +0200 Subject: [PATCH 216/258] #5952 --- src/cmd_context/cmd_context.cpp | 1 + src/cmd_context/cmd_context.h | 1 + src/cmd_context/pdecl.cpp | 59 +++++++++++++++++++++++---------- src/cmd_context/pdecl.h | 17 ++++++---- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 89efc439f..580cc2de4 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1636,6 +1636,7 @@ void cmd_context::pop(unsigned n) { restore_aux_pdecls(s.m_aux_pdecls_lim); restore_assertions(s.m_assertions_lim); restore_psort_inst(s.m_psort_inst_stack_lim); + m_dt_eh.get()->reset(); m_mcs.shrink(m_mcs.size() - n); m_scopes.shrink(new_lvl); if (!m_global_decls) diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 4f9d80a8d..60a6e930b 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -267,6 +267,7 @@ protected: cmd_context & m_owner; datatype_util m_dt_util; public: + void reset() { m_dt_util.reset(); } dt_eh(cmd_context & owner); ~dt_eh() override; void operator()(sort * dt, pdecl* pd) override; diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 7a93382e9..2bf21de3a 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -156,8 +156,8 @@ public: return false; return m_sort == static_cast(other)->m_sort; } - void display(std::ostream & out) const override { - out << m_sort->get_name(); + std::ostream& display(std::ostream & out) const override { + return out << m_sort->get_name(); } }; @@ -180,8 +180,8 @@ public: get_num_params() == other->get_num_params() && m_idx == static_cast(other)->m_idx; } - void display(std::ostream & out) const override { - out << "s_" << m_idx; + std::ostream& display(std::ostream & out) const override { + return out << "s_" << m_idx; } unsigned idx() const { return m_idx; } }; @@ -254,7 +254,7 @@ public: } return true; } - void display(std::ostream & out) const override { + std::ostream& display(std::ostream & out) const override { if (m_args.empty()) { out << m_decl->get_name(); } @@ -267,6 +267,7 @@ public: } out << ")"; } + return out; } }; @@ -342,12 +343,12 @@ void display_sort_args(std::ostream & out, unsigned num_params) { out << ") "; } -void psort_user_decl::display(std::ostream & out) const { +std::ostream& psort_user_decl::display(std::ostream & out) const { out << "(declare-sort " << m_name; display_sort_args(out, m_num_params); if (m_def) m_def->display(out); - out << ")"; + return out << ")"; } // ------------------- @@ -364,8 +365,8 @@ sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * return m.instantiate_datatype(this, m_name, n, s); } -void psort_dt_decl::display(std::ostream & out) const { - out << "(datatype-sort " << m_name << ")"; +std::ostream& psort_dt_decl::display(std::ostream & out) const { + return out << "(datatype-sort " << m_name << ")"; } // ------------------- @@ -410,8 +411,8 @@ sort * psort_builtin_decl::instantiate(pdecl_manager & m, unsigned n, unsigned c } } -void psort_builtin_decl::display(std::ostream & out) const { - out << "(declare-builtin-sort " << m_name << ")"; +std::ostream& psort_builtin_decl::display(std::ostream & out) const { + return out << "(declare-builtin-sort " << m_name << ")"; } void ptype::display(std::ostream & out, pdatatype_decl const * const * dts) const { @@ -615,7 +616,7 @@ sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * } -void pdatatype_decl::display(std::ostream & out) const { +std::ostream& pdatatype_decl::display(std::ostream & out) const { out << "(declare-datatype " << m_name; display_sort_args(out, m_num_params); bool first = true; @@ -631,7 +632,7 @@ void pdatatype_decl::display(std::ostream & out) const { } first = false; } - out << ")"; + return out << ")"; } bool pdatatype_decl::commit(pdecl_manager& m) { @@ -645,9 +646,11 @@ bool pdatatype_decl::commit(pdecl_manager& m) { datatype_decl * d_ptr = dts.m_buffer[0]; sort_ref_vector sorts(m.m()); bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, ps.data(), sorts); + m.notify_mk_datatype(m_name); if (is_ok && m_num_params == 0) { m.notify_new_dt(sorts.get(0), this); } + return is_ok; } @@ -722,6 +725,7 @@ void pdecl_manager::notify_datatype(sort *r, psort_decl* p, unsigned n, sort* co void pdecl_manager::push() { m_notified_lim.push_back(m_notified_trail.size()); + m_datatypes_lim.push_back(m_datatypes_trail.size()); } void pdecl_manager::pop(unsigned n) { @@ -732,6 +736,16 @@ void pdecl_manager::pop(unsigned n) { } m_notified_trail.shrink(new_sz); m_notified_lim.shrink(m_notified_lim.size() - n); + + new_sz = m_datatypes_lim[m_datatypes_lim.size() - n]; + if (new_sz != m_datatypes_trail.size()) { + datatype_util util(m()); + for (unsigned i = m_datatypes_trail.size(); i-- > new_sz; ) + util.plugin().remove(m_datatypes_trail[i]); + } + m_datatypes_trail.shrink(new_sz); + m_datatypes_lim.shrink(m_datatypes_lim.size() - n); + } bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { @@ -751,16 +765,24 @@ bool pdatatypes_decl::commit(pdecl_manager& m) { sort_ref_vector sorts(m.m()); bool is_ok = m.get_dt_plugin()->mk_datatypes(m_datatypes.size(), dts.m_buffer.data(), 0, nullptr, sorts); if (is_ok) { + for (pdatatype_decl* d : m_datatypes) { + m.notify_mk_datatype(d->get_name()); + } for (unsigned i = 0; i < m_datatypes.size(); ++i) { pdatatype_decl* d = m_datatypes[i]; - if (d->get_num_params() == 0) { + if (d->get_num_params() == 0) m.notify_new_dt(sorts.get(i), this); - } } } + return is_ok; } +void pdecl_manager::notify_mk_datatype(symbol const& name) { + m_datatypes_trail.push_back(name); +} + + struct pdecl_manager::sort_info { psort_decl * m_decl; @@ -985,16 +1007,19 @@ void pdecl_manager::del_decl_core(pdecl * p) { } void pdecl_manager::del_decl(pdecl * p) { - TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";); + TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";); if (p->is_psort()) { psort * _p = static_cast(p); if (_p->is_sort_wrapper()) { - m_sort2psort.erase(static_cast(_p)->get_sort()); + sort* s = static_cast(_p)->get_sort(); + m_sort2psort.erase(s); } else { m_table.erase(_p); } + } + del_decl_core(p); } diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index 3a1db06c1..4f9c56825 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -45,7 +45,7 @@ public: unsigned get_id() const { return m_id; } unsigned get_ref_count() const { return m_ref_count; } unsigned hash() const { return m_id; } - virtual void display(std::ostream & out) const {} + virtual std::ostream& display(std::ostream & out) const { return out;} virtual void reset_cache(pdecl_manager& m) {} }; @@ -123,7 +123,7 @@ protected: ~psort_user_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; }; class psort_builtin_decl : public psort_decl { @@ -137,7 +137,7 @@ protected: public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; }; class psort_dt_decl : public psort_decl { @@ -148,7 +148,7 @@ protected: ~psort_dt_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; }; @@ -198,7 +198,7 @@ class paccessor_decl : public pdecl { ptype const & get_type() const { return m_type; } ~paccessor_decl() override {} public: - void display(std::ostream & out) const override { pdecl::display(out); } + std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; } void display(std::ostream & out, pdatatype_decl const * const * dts) const; }; @@ -219,7 +219,7 @@ class pconstructor_decl : public pdecl { constructor_decl * instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s); ~pconstructor_decl() override {} public: - void display(std::ostream & out) const override { pdecl::display(out); } + std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; } void display(std::ostream & out, pdatatype_decl const * const * dts) const; }; @@ -237,7 +237,7 @@ class pdatatype_decl : public psort_decl { ~pdatatype_decl() override {} public: sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; - void display(std::ostream & out) const override; + std::ostream& display(std::ostream & out) const override; bool has_missing_refs(symbol & missing) const; bool has_duplicate_accessors(symbol & repeated) const; bool commit(pdecl_manager& m); @@ -289,6 +289,8 @@ class pdecl_manager { obj_hashtable m_notified; ptr_vector m_notified_trail; unsigned_vector m_notified_lim; + svector m_datatypes_trail; + unsigned_vector m_datatypes_lim; void init_list(); void del_decl_core(pdecl * p); @@ -319,6 +321,7 @@ public: sort * instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s); sort * instantiate(psort * s, unsigned num, sort * const * args); void notify_datatype(sort *r, psort_decl* p, unsigned n, sort* const* s); + void notify_mk_datatype(symbol const& name); void push(); void pop(unsigned n); From 79553261d189b0583f68bbbc48fb9fc81f45128f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 07:02:32 +0200 Subject: [PATCH 217/258] no uname on nt --- scripts/mk_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 6575f0dbf..534910a69 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -621,8 +621,9 @@ elif os.name == 'posix': LINUX_X64=True else: LINUX_X64=False + -if os.uname()[4] == 'arm64': +if os.name == 'posix' and os.uname()[4] == 'arm64': IS_ARCH_ARM64 = True From cb6aba2315e71c0be80451456a75962512fbda92 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:07:56 +0200 Subject: [PATCH 218/258] more arm --- scripts/mk_unix_dist.py | 1 + scripts/mk_util.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 39f48f448..e89ca410f 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -56,6 +56,7 @@ def display_help(): print(" -f, --force force script to regenerate Makefiles.") print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --dotnet-key= sign the .NET assembly with the private key in .") + print(" --arch= set architecture (to arm64) to force arm64 build") print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 534910a69..4d7cedba8 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2436,7 +2436,7 @@ def mk_config(): if ONLY_MAKEFILES: return config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w') - global CXX, CC, GMP, GUARD_CF, STATIC_BIN, GIT_HASH, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, LOG_SYNC, SINGLE_THREADED + global CXX, CC, GMP, GUARD_CF, STATIC_BIN, GIT_HASH, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, LOG_SYNC, SINGLE_THREADED, IS_ARCH_ARM64 if IS_WINDOWS: CXXFLAGS = '/nologo /Zi /D WIN32 /D _WINDOWS /EHsc /GS /Gd /std:c++17' config.write( @@ -2642,6 +2642,7 @@ def mk_config(): if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): CXXFLAGS = '%s -fpic' % CXXFLAGS if IS_OSX and IS_ARCH_ARM64: + print("Setting arm64") CXXFLAGS = '%s -arch arm64' % CXXFLAGS LDFLAGS = '%s -arch arm64' % LDFLAGS SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS From 746a4161af454a89bc6d4308d73e47c1021815cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:24:21 +0200 Subject: [PATCH 219/258] more passing of parameters --- scripts/mk_unix_dist.py | 2 ++ scripts/mk_util.py | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index e89ca410f..9c2a15c67 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -126,6 +126,8 @@ def mk_build_dir(path): opts.append('--git-describe') if PYTHON_ENABLED: opts.append('--python') + if mk_util.IS_ARCH_ARM64: + opts.append('--arm64=true') if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 4d7cedba8..74e761877 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -649,6 +649,7 @@ def display_help(exit_code): print(" -x, --x64 create 64 binary when using Visual Studio.") else: print(" --x86 force 32-bit x86 build on x64 systems.") + print(" --arm64= forcearm64 bit build on/off (supported for Darwin).") print(" -m, --makefiles generate only makefiles.") if IS_WINDOWS: print(" -v, --vsproj generate Visual Studio Project Files.") @@ -691,11 +692,11 @@ def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM global DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED global LINUX_X64, SLOW_OPTIMIZE, LOG_SYNC, SINGLE_THREADED - global GUARD_CF, ALWAYS_DYNAMIC_BASE + global GUARD_CF, ALWAYS_DYNAMIC_BASE, IS_ARCH_ARM64 try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', - ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', + ['build=', 'debug', 'silent', 'x64', 'arm64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded']) except: @@ -718,6 +719,8 @@ def parse_options(): VS_X64 = True elif opt in ('--x86'): LINUX_X64=False + elif opt in ('--arm64'): + IS_ARCH_ARM64 = arg in ('true','on','True','TRUE') elif opt in ('-h', '--help'): display_help(0) elif opt in ('-m', '--makefiles'): From 9533dbaf5c956aee76211b9da5db6b2f49d2259c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:34:52 +0200 Subject: [PATCH 220/258] missing arg specifier --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 74e761877..338dd822f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -696,7 +696,7 @@ def parse_options(): try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', - ['build=', 'debug', 'silent', 'x64', 'arm64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', + ['build=', 'debug', 'silent', 'x64', 'arm64=', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded']) except: From 67434a309670297b435d230fb054e49f3c8e446d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:40:55 +0200 Subject: [PATCH 221/258] again --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 338dd822f..34ca9a38a 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -695,7 +695,7 @@ def parse_options(): global GUARD_CF, ALWAYS_DYNAMIC_BASE, IS_ARCH_ARM64 try: options, remainder = getopt.gnu_getopt(sys.argv[1:], - 'b:df:sxhmcvtnp:gj', + 'b:df:sxa:hmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'arm64=', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded']) From f3789e21a349626ae351abd4c1d38a24e57387a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:42:18 +0200 Subject: [PATCH 222/258] id doesn't use mk_util --- src/api/python/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt index e791a2f11..067a25e8c 100644 --- a/src/api/python/CMakeLists.txt +++ b/src/api/python/CMakeLists.txt @@ -42,8 +42,6 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3core.py" ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} - # FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency - "${PROJECT_SOURCE_DIR}/scripts/mk_util.py" COMMENT "Generating z3core.py" ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} ) From 3821eb4134c977a4a35f57d5384de843d4c2991e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:47:38 +0200 Subject: [PATCH 223/258] fpflags --- scripts/mk_util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 34ca9a38a..761de8b26 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -279,10 +279,13 @@ def test_gmp(cc): def test_fpmath(cc): - global FPMATH_FLAGS + global FPMATH_FLAGS, IS_ARCH_ARM64, IS_OSX if FPMATH_ENABLED == "False": FPMATH_FLAGS="" return "Disabled" + if IS_ARCH_ARM64 and IS_OSX: + FPMATH_FLAGS = "" + return "Disabled-ARM64" if is_verbose(): print("Testing floating point support...") t = TempFile('tstsse.cpp') From 91ca02864cb8552c837a848e8e681373720f6e48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 14:59:22 +0200 Subject: [PATCH 224/258] arm64 Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist.py | 4 +++- scripts/nightly.yaml | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 9c2a15c67..97de725e9 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -181,7 +181,9 @@ def get_os_name(): def get_z3_name(): major, minor, build, revision = get_version() - if sys.maxsize >= 2**32: + if mk_util.IS_ARCH_ARM64: + platform = "arm64" + elif sys.maxsize >= 2**32: platform = "x64" else: platform = "x86" diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4296cab08..1ba0ea5af 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -180,6 +180,11 @@ stages: inputs: artifact: 'Mac' path: $(Agent.TempDirectory)\package + - task: DownloadPipelineArtifact@2 + displayName: 'Download macOS Arm64 Build' + inputs: + artifact: 'MacArm64' + path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x @@ -435,6 +440,11 @@ stages: inputs: artifactName: 'Mac' targetPath: tmp + - task: DownloadPipelineArtifact@2 + displayName: "Download MacArm64" + inputs: + artifactName: 'MacArm64' + targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu" inputs: From fbd35fb58d333b28208eb9da696aa10824e99370 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 16:55:39 +0200 Subject: [PATCH 225/258] skip unit tests for arm --- scripts/nightly.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 1ba0ea5af..488e5aedf 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -31,7 +31,6 @@ stages: steps: - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 - script: git clone https://github.com/z3prover/z3test z3test - - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@1 inputs: From d6d9b25c6854989afcb2b7a72f92759ec2cecde9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Apr 2022 17:12:20 +0200 Subject: [PATCH 226/258] Allow adding constraints in the model_eh callback --- src/opt/opt_context.cpp | 23 +++++++++++++++++------ src/opt/opt_context.h | 1 + 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3551686f7..02cd90113 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -185,17 +185,27 @@ namespace opt { } void context::set_hard_constraints(expr_ref_vector const& fmls) { - if (m_scoped_state.set(fmls)) { + if (m_calling_on_model) { + for (expr* f : fmls) + add_hard_constraint(f); + return; + } + if (m_scoped_state.set(fmls)) + clear_state(); + } + + void context::add_hard_constraint(expr* f) { + if (m_calling_on_model) + get_solver().assert_expr(f); + else { + m_scoped_state.add(f); clear_state(); } } - void context::add_hard_constraint(expr* f) { - m_scoped_state.add(f); - clear_state(); - } - void context::add_hard_constraint(expr* f, expr* t) { + if (m_calling_on_model) + throw default_exception("adding soft constraints is not supported during callbacks"); m_scoped_state.m_asms.push_back(t); m_scoped_state.add(m.mk_implies(t, f)); clear_state(); @@ -389,6 +399,7 @@ namespace opt { model_ref md = m->copy(); if (!m_model_fixed.contains(md.get())) fix_model(md); + flet _calling(m_calling_on_model, true); m_on_model_eh(m_on_model_ctx, md); m_model_fixed.pop_back(); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index dd717c392..1e950174a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -165,6 +165,7 @@ namespace opt { ast_manager& m; on_model_t m_on_model_ctx; std::function m_on_model_eh; + bool m_calling_on_model = false; arith_util m_arith; bv_util m_bv; expr_ref_vector m_hard_constraints; From c98eda03f7c834f771f7e5f1ddfc5517c1029dbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 06:55:31 +0200 Subject: [PATCH 227/258] nightly osx arm64 wheel --- scripts/nightly.yaml | 10 ++++++++-- src/api/python/setup.py | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 488e5aedf..ad64d05b7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -399,7 +399,12 @@ stages: inputs: artifactName: 'Mac' targetPath: $(Agent.TempDirectory) - - script: cd $(Agent.TempDirectory); mkdir osx-bin; cd osx-bin; unzip ../*osx*.zip + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: 'MacArm64' + targetPath: $(Agent.TempDirectory) + - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*osx*x64.zip + - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*osx*arm64.zip - script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*glibc*.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip @@ -409,7 +414,8 @@ stages: - script: cd src/api/python; echo $(Agent.TempDirectory)/linux-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - task: PublishPipelineArtifact@0 inputs: artifactName: 'Python packages' diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 8c73c29e6..796f30e6b 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -279,8 +279,10 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: osver = RELEASE_METADATA[3] if osver.count('.') > 1: osver = '.'.join(osver.split('.')[:2]) - if arch == 'x64': + if arch == 'x64': plat_name ='macosx_%s_x86_64' % osver.replace('.', '_') + elif arc == 'arm64': + plat_name ='macosx_%s_arm64' % osver.replace('.', '_') else: raise Exception(f"idk how os {distos} {osver} works. what goes here?") else: From fe834b9e4e5519891da0d053ea9caea4640aaaa5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 07:40:48 +0200 Subject: [PATCH 228/258] update regex --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index ad64d05b7..0add769b9 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -403,8 +403,8 @@ stages: inputs: artifactName: 'MacArm64' targetPath: $(Agent.TempDirectory) - - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*osx*x64.zip - - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*osx*arm64.zip + - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip + - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*glibc*.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip From 005b8e3cf85d00dd7360d901580aba9925725c56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 08:28:22 +0200 Subject: [PATCH 229/258] arc -> arch --- src/api/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 796f30e6b..1b455bb56 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -281,7 +281,7 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: osver = '.'.join(osver.split('.')[:2]) if arch == 'x64': plat_name ='macosx_%s_x86_64' % osver.replace('.', '_') - elif arc == 'arm64': + elif arch == 'arm64': plat_name ='macosx_%s_arm64' % osver.replace('.', '_') else: raise Exception(f"idk how os {distos} {osver} works. what goes here?") From 405a26c5856ba726c31582eaf51103d01f1b51a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 09:55:02 +0200 Subject: [PATCH 230/258] allow adding constraints during on_model --- src/opt/maxres.cpp | 17 ++++++++--------- src/opt/maxsmt.cpp | 14 +++++++++++++- src/opt/maxsmt.h | 3 +++ src/opt/opt_context.cpp | 11 ++++++++++- src/sat/sat_solver.cpp | 2 ++ 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 27b3b7260..1b4348105 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -791,11 +791,10 @@ public: improve_model(mdl); mdl->set_model_completion(true); unsigned correction_set_size = 0; - for (expr* a : m_asms) { - if (mdl->is_false(a)) { + for (expr* a : m_asms) + if (mdl->is_false(a)) ++correction_set_size; - } - } + if (!m_csmodel.get() || correction_set_size < m_correction_set_size) { m_csmodel = mdl; m_correction_set_size = correction_set_size; @@ -810,22 +809,22 @@ public: return; } - if (!m_c.verify_model(m_index, mdl.get(), upper)) { + if (!m_c.verify_model(m_index, mdl.get(), upper)) return; - } + unsigned num_assertions = s().get_num_assertions(); m_model = mdl; m_c.model_updated(mdl.get()); TRACE("opt", tout << "updated upper: " << upper << "\n";); - for (soft& s : m_soft) { + for (soft& s : m_soft) s.set_value(m_model->is_true(s.s)); - } verify_assignment(); - m_upper = upper; + if (num_assertions == s().get_num_assertions()) + m_upper = upper; trace(); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 6a8a2ee35..bf25f3f95 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -50,7 +50,13 @@ namespace opt { void maxsmt_solver_base::updt_params(params_ref& p) { m_params.copy(p); - } + } + + void maxsmt_solver_base::reset_upper() { + m_upper = m_lower; + for (soft& s : m_soft) + m_upper += s.weight; + } solver& maxsmt_solver_base::s() { return m_c.get_solver(); @@ -289,6 +295,12 @@ namespace opt { } } + void maxsmt::reset_upper() { + if (m_msolver) { + m_msolver->reset_upper(); + m_upper = m_msolver->get_upper(); + } + } void maxsmt::verify_assignment() { // TBD: have to use a different solver diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index ad355cc9e..5bf637dde 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -103,6 +103,8 @@ namespace opt { }; lbool find_mutexes(obj_map& new_soft); + + void reset_upper(); protected: @@ -153,6 +155,7 @@ namespace opt { void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; void model_updated(model* mdl); + void reset_upper(); private: bool is_maxsat_problem(weights_t& ws) const; void verify_assignment(); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 02cd90113..8848b61c9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -195,13 +195,22 @@ namespace opt { } void context::add_hard_constraint(expr* f) { - if (m_calling_on_model) + if (m_calling_on_model) { get_solver().assert_expr(f); + for (auto const& [k, v] : m_maxsmts) + v->reset_upper(); + for (unsigned i = 0; i < num_objectives(); ++i) { + auto const& o = m_scoped_state.m_objectives[i]; + if (o.m_type != O_MAXSMT) + m_optsmt.update_upper(o.m_index, inf_eps::infinity()); + } + } else { m_scoped_state.add(f); clear_state(); } } + void context::add_hard_constraint(expr* f, expr* t) { if (m_calling_on_model) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5505cfa70..4a254ac06 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3818,6 +3818,8 @@ namespace sat { void solver::move_to_front(bool_var b) { if (b >= num_vars()) return; + if (m_case_split_queue.empty()) + return; bool_var next = m_case_split_queue.min_var(); auto next_act = m_activity[next]; set_activity(b, next_act + 1); From 011c1b2dd2bd394ac043668e289bfdabbe2b1f27 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 12:06:27 +0200 Subject: [PATCH 231/258] remove refs to bare_str --- src/api/api_ast.cpp | 2 +- src/api/api_log.cpp | 2 +- src/api/api_tactic.cpp | 6 +-- src/ast/ast_smt2_pp.cpp | 12 ++---- src/cmd_context/basic_cmds.cpp | 2 +- src/muz/fp/datalog_parser.cpp | 40 ++++++++++--------- src/muz/rel/dl_finite_product_relation.cpp | 2 +- src/muz/rel/dl_instruction.cpp | 20 +++++----- src/muz/rel/dl_table_relation.cpp | 2 +- src/muz/rel/rel_context.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 5 +-- 11 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index d5de6b5fb..8144c2baf 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -355,7 +355,7 @@ extern "C" { return mk_c(c)->mk_external_string(buffer.str()); } else { - return mk_c(c)->mk_external_string(_s.bare_str()); + return mk_c(c)->mk_external_string(_s.str()); } Z3_CATCH_RETURN(""); } diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index c1864ae8c..ed5f68e8a 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -88,7 +88,7 @@ void Sy(Z3_symbol sym) { *g_z3_log << "# " << s.get_num(); } else { - *g_z3_log << "$ |" << ll_escaped{s.bare_str()} << '|'; + *g_z3_log << "$ |" << ll_escaped{s.str().c_str()} << '|'; } *g_z3_log << std::endl; } diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 45073cdb1..f67a373dd 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -331,8 +331,8 @@ extern "C" { if (idx >= mk_c(c)->num_tactics()) { SET_ERROR_CODE(Z3_IOB, nullptr); return ""; - } - return mk_c(c)->get_tactic(idx)->get_name().bare_str(); + } + return mk_c(c)->mk_external_string(mk_c(c)->get_tactic(idx)->get_name().str().c_str()); Z3_CATCH_RETURN(""); } @@ -352,7 +352,7 @@ extern "C" { SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } - return mk_c(c)->get_probe(idx)->get_name().bare_str(); + return mk_c(c)->mk_external_string(mk_c(c)->get_probe(idx)->get_name().str().c_str()); Z3_CATCH_RETURN(""); } diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 9854195a4..59f9ecda6 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -47,18 +47,14 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len, bo len = static_cast(str.length()); return mk_string(m, str); } - else if (s.is_numerical()) { - std::string str = s.str(); - len = static_cast(str.length()); - return mk_string(m, str); - } - else if (!s.bare_str()) { + else if (s.is_null()) { len = 4; return mk_string(m, "null"); } else { - len = static_cast(strlen(s.bare_str())); - return mk_string(m, s.bare_str()); + std::string str = s.str(); + len = static_cast(str.length()); + return mk_string(m, str); } } diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index afe800af6..f3bd0ed57 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -58,7 +58,7 @@ public: cmd * c = ctx.find_cmd(s); if (c == nullptr) { std::string err_msg("unknown command '"); - err_msg = err_msg + s.bare_str() + "'"; + err_msg = err_msg + s.str() + "'"; throw cmd_exception(std::move(err_msg)); } m_cmds.push_back(s); diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 899ec497c..030d88d71 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -777,6 +777,7 @@ protected: // Sym ::= String | NUM | Var // dtoken parse_infix(dtoken tok1, char const* td, app_ref& pred) { + std::string td1_(td); symbol td1(td); expr_ref v1(m), v2(m); sort* s = nullptr; @@ -793,12 +794,12 @@ protected: if (tok1 == TK_ID) { expr* _v1 = nullptr; - m_vars.find(td1.bare_str(), _v1); + m_vars.find(td1_, _v1); v1 = _v1; } if (tok3 == TK_ID) { expr* _v2 = nullptr; - m_vars.find(td2.bare_str(), _v2); + m_vars.find(td, _v2); v2 = _v2; } if (!v1 && !v2) { @@ -950,18 +951,19 @@ protected: break; } case TK_ID: { - symbol data (m_lexer->get_token_data()); - if (is_var(data.bare_str())) { + char const* d = m_lexer->get_token_data(); + symbol data (d); + if (is_var(d)) { unsigned idx = 0; expr* v = nullptr; - if (!m_vars.find(data.bare_str(), v)) { + if (!m_vars.find(d, v)) { idx = m_num_vars++; v = m.mk_var(idx, s); - m_vars.insert(data.bare_str(), v); + m_vars.insert(d, v); } else if (s != v->get_sort()) { throw default_exception(default_exception::fmt(), "sort: %s expected, but got: %s\n", - s->get_name().bare_str(), v->get_sort()->get_name().bare_str()); + s->get_name().str().c_str(), v->get_sort()->get_name().str().c_str()); } args.push_back(v); } @@ -1075,21 +1077,21 @@ protected: } sort * register_finite_sort(symbol name, uint64_t domain_size, context::sort_kind k) { - if(m_sort_dict.contains(name.bare_str())) { - throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str()); + if(m_sort_dict.contains(name.str().c_str())) { + throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str()); } sort * s = m_decl_util.mk_sort(name, domain_size); m_context.register_finite_sort(s, k); - m_sort_dict.insert(name.bare_str(), s); + m_sort_dict.insert(name.str(), s); return s; } sort * register_int_sort(symbol name) { - if(m_sort_dict.contains(name.bare_str())) { - throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str()); + if(m_sort_dict.contains(name.str().c_str())) { + throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str()); } sort * s = m_arith.mk_int(); - m_sort_dict.insert(name.bare_str(), s); + m_sort_dict.insert(name.str(), s); return s; } @@ -1105,8 +1107,8 @@ protected: app * res; if(m_arith.is_int(s)) { uint64_t val; - if (!string_to_uint64(name.bare_str(), val)) { - throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.bare_str()); + if (!string_to_uint64(name.str().c_str(), val)) { + throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.str().c_str()); } res = m_arith.mk_numeral(rational(val, rational::ui64()), s); } @@ -1288,7 +1290,7 @@ private: uint64_set & sort_content = *e->get_data().m_value; if(!sort_content.contains(num)) { warning_msg("symbol number %I64u on line %d in file %s does not belong to sort %s", - num, m_current_line, m_current_file.c_str(), s->get_name().bare_str()); + num, m_current_line, m_current_file.c_str(), s->get_name().str().c_str()); return false; } if(!m_use_map_names) { @@ -1366,7 +1368,7 @@ private: func_decl * pred = m_context.try_get_predicate_decl(predicate_name); if(!pred) { throw default_exception(default_exception::fmt(), "tuple file %s for undeclared predicate %s", - m_current_file.c_str(), predicate_name.bare_str()); + m_current_file.c_str(), predicate_name.str().c_str()); } unsigned pred_arity = pred->get_arity(); sort * const * arg_sorts = pred->get_domain(); @@ -1531,9 +1533,9 @@ private: if(m_use_map_names) { auto const & value = m_number_names.insert_if_not_there(num, el_name); - if (value!=el_name) { + if (value != el_name) { warning_msg("mismatch of number names on line %d in file %s. old: \"%s\" new: \"%s\"", - m_current_line, fname.c_str(), value.bare_str(), el_name.bare_str()); + m_current_line, fname.c_str(), value.str().c_str(), el_name.str().c_str()); } } } diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 8a4b86e6d..07921a3be 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -64,7 +64,7 @@ namespace datalog { } symbol finite_product_relation_plugin::get_name(relation_plugin & inner_plugin) { - std::string str = std::string("fpr_")+inner_plugin.get_name().bare_str(); + std::string str = std::string("fpr_")+inner_plugin.get_name().str(); return symbol(str.c_str()); } diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 0df03172f..63846e7d5 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -213,10 +213,10 @@ namespace datalog { return true; } void make_annotations(execution_context & ctx) override { - ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str()); + ctx.set_register_annotation(m_reg, m_pred->get_name().str().c_str()); } std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override { - const char * rel_name = m_pred->get_name().bare_str(); + auto rel_name = m_pred->get_name(); if (m_store) { return out << "store " << m_reg << " into " << rel_name; } @@ -378,7 +378,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported join operation on relations of kinds %s and %s", - r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str()); + r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str()); } store_fn(r1, r2, fn); } @@ -441,7 +441,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_equal operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -490,7 +490,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_identical operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -537,7 +537,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_interpreted operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -594,7 +594,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported filter_interpreted_and_project operation on a relation of kind %s", - reg.get_plugin().get_name().bare_str()); + reg.get_plugin().get_name().str().c_str()); } store_fn(reg, fn); } @@ -837,7 +837,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported join-project operation on relations of kinds %s and %s", - r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str()); + r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str()); } store_fn(r1, r2, fn); } @@ -910,7 +910,7 @@ namespace datalog { if (!fn) { throw default_exception(default_exception::fmt(), "trying to perform unsupported select_equal_and_project operation on a relation of kind %s", - r.get_plugin().get_name().bare_str()); + r.get_plugin().get_name().str().c_str()); } store_fn(r, fn); } @@ -1076,7 +1076,7 @@ namespace datalog { return true; } std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override { - return out << "mark_saturated " << m_pred->get_name().bare_str(); + return out << "mark_saturated " << m_pred->get_name(); } void make_annotations(execution_context & ctx) override { } diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index de55998f8..8a69f8f85 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -33,7 +33,7 @@ namespace datalog { // ----------------------------------- symbol table_relation_plugin::create_plugin_name(const table_plugin &p) { - std::string name = std::string("tr_") + p.get_name().bare_str(); + std::string name = std::string("tr_") + p.get_name().str(); return symbol(name.c_str()); } diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 957c85adb..76411a290 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -157,7 +157,7 @@ namespace datalog { //IF_VERBOSE(3, m_context.display_smt2(0,0,verbose_stream());); if (m_context.print_aig().is_non_empty_string()) { - const char *filename = m_context.print_aig().bare_str(); + std::string filename = m_context.print_aig().str(); aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts); std::ofstream strm(filename, std::ios_base::binary); aig(strm); diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 52df38247..0c304aa3f 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -143,10 +143,9 @@ public: tactic_ref t; if (tp.default_tactic() != symbol::null && !tp.default_tactic().is_numerical() && - tp.default_tactic().bare_str() && - tp.default_tactic().bare_str()[0]) { + tp.default_tactic().str()[0]) { cmd_context ctx(false, &m, l); - std::istringstream is(tp.default_tactic().bare_str()); + std::istringstream is(tp.default_tactic().str()); char const* file_name = ""; sexpr_ref se = parse_sexpr(ctx, is, p, file_name); if (se) { From f55b23322860a8e186ae919daa4796ac4850a82e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Apr 2022 12:06:39 +0200 Subject: [PATCH 232/258] #5778 --- src/sat/smt/arith_solver.cpp | 9 +++++---- src/sat/smt/q_model_fixer.cpp | 6 ++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 5a102fa14..e02a42979 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -549,13 +549,14 @@ namespace arith { found_compatible = false; for (; it != end; ++it) { api_bound* a2 = *it; - if (a1 == a2) continue; - if (a2->get_bound_kind() != kind) continue; + if (a1 == a2) + continue; + if (a2->get_bound_kind() != kind) + continue; rational const& k2(a2->get_value()); found_compatible = true; - if (k1 < k2) { + if (k1 < k2) return it; - } } return end; } diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index 456525c42..cdea60d23 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -184,6 +184,8 @@ namespace q { for (euf::enode* n : ctx.get_egraph().enodes_of(f)) { expr* t = n->get_arg(idx)->get_expr(); values.push_back(mdl(t)); + if (!m.is_value(values.back())) + return expr_ref(m.mk_var(idx, srt), m); md->v2t.insert(values.back(), t); md->t2v.insert(t, values.back()); } @@ -299,6 +301,10 @@ namespace q { auto term = [&](unsigned j) { return md->v2t[md->values[j]]; }; + + for (unsigned j = 0; j < sz; ++j) + std::cout << mk_pp(md->values[j], m) << "\n"; + expr* arg = t->get_arg(i); From 0b20a4ebf4b8e3e0188ccbb5dad9b51a88966f04 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Sat, 9 Apr 2022 21:46:21 +0200 Subject: [PATCH 233/258] Added rewriting distinct with bitvectors to false if bit-size is too low (#5956) * Fixed problem with registering bitvector functions * Added rewriting distinct with bitvectors to false if bit-size is too low * Removed debug output * Incorporated Nikolaj's comments * Simplifications --- src/ast/rewriter/bv_rewriter.cpp | 15 +++++++++++++++ src/ast/rewriter/bv_rewriter.h | 3 ++- src/ast/rewriter/th_rewriter.cpp | 20 +++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 073885c21..1fdd7bd14 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2803,6 +2803,21 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu return BR_FAILED; } +br_status bv_rewriter::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) { + if (num_args <= 1) { + result = m().mk_true(); + return BR_DONE; + } + unsigned sz = get_bv_size(args[0]); + // check if num_args > 2^sz + if (sz >= 32) + return BR_FAILED; + if (num_args <= 1u << sz) + return BR_FAILED; + result = m().mk_false(); + return BR_DONE; +} + br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result) { SASSERT(num == 2); unsigned bv_sz; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 7f0c67540..88d952c06 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -180,7 +180,8 @@ public: bool is_urem_any(expr * e, expr * & dividend, expr * & divisor); br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result); - br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resul); + br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result); + br_status mk_distinct(unsigned num_args, expr * const * args, expr_ref & result); bool hi_div0() const { return m_hi_div0; } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 22d6a83b7..9cf9fc810 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -60,7 +60,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr_substitution * m_subst = nullptr; unsigned long long m_max_memory; // in bytes bool m_new_subst = false; - unsigned m_max_steps = UINT_MAX; + unsigned m_max_steps = UINT_MAX; bool m_pull_cheap_ite = true; bool m_flat = true; bool m_cache_all = false; @@ -180,7 +180,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { // theory dispatch for = SASSERT(num == 2); family_id s_fid = args[0]->get_sort()->get_family_id(); - if (s_fid == m_a_rw.get_fid()) + if (s_fid == m_a_rw.get_fid()) st = m_a_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_bv_rw.get_fid()) st = m_bv_rw.mk_eq_core(args[0], args[1], result); @@ -193,10 +193,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { else if (s_fid == m_seq_rw.get_fid()) st = m_seq_rw.mk_eq_core(args[0], args[1], result); if (st != BR_FAILED) - return st; - } - if (k == OP_EQ) { - SASSERT(num == 2); + return st; st = apply_tamagotchi(args[0], args[1], result); if (st != BR_FAILED) return st; @@ -210,16 +207,21 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return st; } if ((k == OP_AND || k == OP_OR) && m_seq_rw.u().has_re()) { - st = m_seq_rw.mk_bool_app(f, num, args, result); + st = m_seq_rw.mk_bool_app(f, num, args, result); if (st != BR_FAILED) return st; } - if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) && + if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) && to_app(args[0])->get_family_id() == m_seq_rw.get_fid()) { st = m_seq_rw.mk_eq_core(args[0], args[1], result); if (st != BR_FAILED) return st; } + if (k == OP_DISTINCT && num > 0 && m_bv_rw.is_bv(args[0])) { + st = m_bv_rw.mk_distinct(num, args, result); + if (st != BR_FAILED) + return st; + } return m_b_rw.mk_app_core(f, num, args, result); } @@ -250,7 +252,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { if (fid == m_seq_rw.get_fid()) return m_seq_rw.mk_app_core(f, num, args, result); if (fid == m_char_rw.get_fid()) - return m_char_rw.mk_app_core(f, num, args, result); + return m_char_rw.mk_app_core(f, num, args, result); if (fid == m_rec_rw.get_fid()) return m_rec_rw.mk_app_core(f, num, args, result); return BR_FAILED; From 4f4e9a9963309518c7cdd92a01ae5429533d6369 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 11 Apr 2022 02:40:03 -0400 Subject: [PATCH 234/258] fix a tiny typo (#5960) A dot. --- doc/website.dox.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/website.dox.in b/doc/website.dox.in index 69395492e..f4caa1277 100644 --- a/doc/website.dox.in +++ b/doc/website.dox.in @@ -4,7 +4,7 @@ Z3 is a high-performance theorem prover being developed at Microsoft Research. - The Z3 website is at http://github.com/z3prover.. + The Z3 website is at http://github.com/z3prover. This website hosts the automatically generated documentation for the Z3 APIs. From f43d9d00d4ba7ee040d7e3736a848926a842c082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bour?= Date: Mon, 11 Apr 2022 13:38:20 +0200 Subject: [PATCH 235/258] Z3_add_rec_def body is not a macro (#5963) --- src/api/api_ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 8144c2baf..7ee95afc8 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -164,7 +164,7 @@ extern "C" { return; } recfun_replace replace(m); - p.set_definition(replace, pd, true, n, _vars.data(), abs_body); + p.set_definition(replace, pd, false, n, _vars.data(), abs_body); Z3_CATCH; } From b0d8b27f37cf184fe632ec84f19785dc20a9ff80 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:50:13 +0200 Subject: [PATCH 236/258] Fixed registering expressions in push/pop (#5964) * Fixed registering expressions in push/pop * Reused existing function --- src/api/api_solver.cpp | 4 ++-- src/api/c++/z3++.h | 17 +++++++++++------ src/api/z3_api.h | 4 ++-- src/sat/smt/user_solver.cpp | 4 ++-- src/smt/theory_user_propagator.cpp | 13 ++++++++----- src/tactic/user_propagator_base.h | 12 ++++++------ 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 99d332724..948064af6 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -883,8 +883,8 @@ extern "C" { Z3_TRY; RESET_ERROR_CODE(); init_solver(c, s); - user_propagator::push_eh_t _push = push_eh; - user_propagator::pop_eh_t _pop = pop_eh; + user_propagator::push_eh_t _push = (void(*)(void*,user_propagator::callback*)) push_eh; + user_propagator::pop_eh_t _pop = (void(*)(void*,user_propagator::callback*,unsigned)) pop_eh; user_propagator::fresh_eh_t _fresh = [=](void * user_ctx, ast_manager& m, user_propagator::context_obj*& _ctx) { ast_context_params params; params.set_foreign_manager(&m); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4d60de433..101fa04a3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -3964,18 +3964,23 @@ namespace z3 { } }; - static void push_eh(void* p) { + static void push_eh(void* _p, Z3_solver_callback cb) { + user_propagator_base* p = static_cast(_p); + scoped_cb _cb(p, cb); static_cast(p)->push(); } - static void pop_eh(void* p, unsigned num_scopes) { - static_cast(p)->pop(num_scopes); + static void pop_eh(void* _p, Z3_solver_callback cb, unsigned num_scopes) { + user_propagator_base* p = static_cast(_p); + scoped_cb _cb(p, cb); + static_cast(_p)->pop(num_scopes); } - static void* fresh_eh(void* p, Z3_context ctx) { + static void* fresh_eh(void* _p, Z3_context ctx) { + user_propagator_base* p = static_cast(_p); context* c = new context(ctx); - static_cast(p)->subcontexts.push_back(c); - return static_cast(p)->fresh(*c); + p->subcontexts.push_back(c); + return p->fresh(*c); } static void fixed_eh(void* _p, Z3_solver_callback cb, Z3_ast _var, Z3_ast _value) { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d7dd0a332..8a610bc6d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1434,8 +1434,8 @@ Z3_DECLARE_CLOSURE(Z3_error_handler, void, (Z3_context c, Z3_error_code e)); /** \brief callback functions for user propagator. */ -Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx)); -Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, unsigned num_scopes)); +Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx, Z3_solver_callback cb)); +Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, Z3_solver_callback cb, unsigned num_scopes)); Z3_DECLARE_CLOSURE(Z3_fresh_eh, void*, (void* ctx, Z3_context new_context)); Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t, Z3_ast value)); Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 6b3eb6718..d24af253e 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -88,7 +88,7 @@ namespace user_solver { void solver::push_core() { th_euf_solver::push_core(); m_prop_lim.push_back(m_prop.size()); - m_push_eh(m_user_context); + m_push_eh(m_user_context, this); } void solver::pop_core(unsigned num_scopes) { @@ -96,7 +96,7 @@ namespace user_solver { unsigned old_sz = m_prop_lim.size() - num_scopes; m_prop.shrink(m_prop_lim[old_sz]); m_prop_lim.shrink(old_sz); - m_pop_eh(m_user_context, num_scopes); + m_pop_eh(m_user_context, this, num_scopes); } void solver::propagate_consequence(prop_info const& prop) { diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 7c53aa8eb..daded32c7 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -25,6 +25,7 @@ using namespace smt; theory_user_propagator::theory_user_propagator(context& ctx): theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name())), m_var2expr(ctx.get_manager()), + m_push_popping(false), m_to_add(ctx.get_manager()) {} @@ -38,7 +39,7 @@ void theory_user_propagator::force_push() { theory::push_scope_eh(); m_prop_lim.push_back(m_prop.size()); m_to_add_lim.push_back(m_to_add.size()); - m_push_eh(m_user_context); + m_push_eh(m_user_context, this); } } @@ -122,7 +123,8 @@ final_check_status theory_user_propagator::final_check_eh() { if (!(bool)m_final_eh) return FC_DONE; force_push(); - unsigned sz = m_prop.size(); + unsigned sz1 = m_prop.size(); + unsigned sz2 = m_expr2var.size(); try { m_final_eh(m_user_context, this); } @@ -130,7 +132,8 @@ final_check_status theory_user_propagator::final_check_eh() { throw default_exception("Exception thrown in \"final\"-callback"); } propagate(); - bool done = (sz == m_prop.size()) && !ctx.inconsistent(); + // check if it became inconsistent or something new was propagated/registered + bool done = !can_propagate() && !ctx.inconsistent(); return done ? FC_DONE : FC_CONTINUE; } @@ -169,11 +172,11 @@ void theory_user_propagator::pop_scope_eh(unsigned num_scopes) { old_sz = m_to_add_lim.size() - num_scopes; m_to_add.shrink(m_to_add_lim[old_sz]); m_to_add_lim.shrink(old_sz); - m_pop_eh(m_user_context, num_scopes); + m_pop_eh(m_user_context, this, num_scopes); } bool theory_user_propagator::can_propagate() { - return m_qhead < m_prop.size() || !m_to_add.empty(); + return m_qhead < m_prop.size() || m_to_add_qhead < m_to_add.size(); } void theory_user_propagator::propagate_consequence(prop_info const& prop) { diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 07270ffe6..02a027762 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -17,13 +17,13 @@ namespace user_propagator { virtual ~context_obj() = default; }; - typedef std::function final_eh_t; - typedef std::function fixed_eh_t; - typedef std::function eq_eh_t; + typedef std::function final_eh_t; + typedef std::function fixed_eh_t; + typedef std::function eq_eh_t; typedef std::function fresh_eh_t; - typedef std::function push_eh_t; - typedef std::function pop_eh_t; - typedef std::function created_eh_t; + typedef std::function push_eh_t; + typedef std::function pop_eh_t; + typedef std::function created_eh_t; class plugin : public decl_plugin { From c996a66da04c882bc47dccacbf3507f1ab56f8e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Apr 2022 17:05:49 +0200 Subject: [PATCH 237/258] separate pre-processing, add callback parameter to push/pop in python API --- scripts/update_api.py | 4 +- src/api/python/z3/z3.py | 12 ++- src/opt/CMakeLists.txt | 1 + src/opt/maxlex.cpp | 18 ++--- src/opt/maxlex.h | 4 +- src/opt/maxres.cpp | 25 +++--- src/opt/maxres.h | 4 +- src/opt/maxsmt.cpp | 131 ++++++++------------------------ src/opt/maxsmt.h | 42 +++++----- src/opt/opt_mux.h | 32 ++++++++ src/opt/opt_preprocess.cpp | 102 +++++++++++++++++++++++++ src/opt/opt_preprocess.h | 38 +++++++++ src/opt/sortmax.cpp | 41 ++++------ src/opt/wmax.cpp | 28 +++---- src/opt/wmax.h | 4 +- src/sat/smt/euf_internalize.cpp | 1 + 16 files changed, 287 insertions(+), 200 deletions(-) create mode 100644 src/opt/opt_mux.h create mode 100644 src/opt/opt_preprocess.cpp create mode 100644 src/opt/opt_preprocess.h diff --git a/scripts/update_api.py b/scripts/update_api.py index ab1b4d6fd..d4d1ab0e0 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1820,8 +1820,8 @@ _error_handler_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint) _lib.Z3_set_error_handler.restype = None _lib.Z3_set_error_handler.argtypes = [ContextObj, _error_handler_type] -push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p) -pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint) +push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) +pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint) fresh_eh_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) fixed_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 6f4dcf430..d3d6067c3 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11237,12 +11237,16 @@ def ensure_prop_closures(): _prop_closures = PropClosures() -def user_prop_push(ctx): - _prop_closures.get(ctx).push() +def user_prop_push(ctx, cb): + prop = _prop_closures.get(ctx) + prop.cb = cb + prop.push() -def user_prop_pop(ctx, num_scopes): - _prop_closures.get(ctx).pop(num_scopes) +def user_prop_pop(ctx, cb, num_scopes): + prop = _prop_closures.get(ctx) + prop.cb = cb + pop(num_scopes) def user_prop_fresh(id, ctx): diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index d88d11c0f..c652bcaea 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -8,6 +8,7 @@ z3_add_component(opt opt_lns.cpp opt_pareto.cpp opt_parse.cpp + opt_preprocess.cpp optsmt.cpp opt_solver.cpp pb_sls.cpp diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 46c7104d5..82eee6f5e 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -26,15 +26,15 @@ Author: namespace opt { - bool is_maxlex(weights_t & _ws) { - vector ws(_ws); - std::sort(ws.begin(), ws.end()); + bool is_maxlex(vector const & _ws) { + vector ws(_ws); + std::sort(ws.begin(), ws.end(), [&](soft const& s1, soft const& s2) { return s1.weight < s2.weight; }); ws.reverse(); rational sum(0); - for (rational const& w : ws) { + for (auto const& [e, w, t] : ws) { sum += w; } - for (rational const& w : ws) { + for (auto const& [e, w, t] : ws) { if (sum > w + w) return false; sum -= w; } @@ -185,8 +185,8 @@ namespace opt { public: - maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& s): - maxsmt_solver_base(c, ws, s), + maxlex(maxsat_context& c, unsigned id, vector& s): + maxsmt_solver_base(c, s), m(c.get_manager()), m_c(c) { // ensure that soft constraints are sorted with largest soft constraints first. @@ -210,8 +210,8 @@ namespace opt { } }; - maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft) { - return alloc(maxlex, c, id, ws, soft); + maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxlex, c, id, soft); } } diff --git a/src/opt/maxlex.h b/src/opt/maxlex.h index b5c1a6e20..fc30b1fd8 100644 --- a/src/opt/maxlex.h +++ b/src/opt/maxlex.h @@ -21,9 +21,9 @@ Notes: namespace opt { - bool is_maxlex(weights_t & ws); + bool is_maxlex(vector const & ws); - maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector& soft); }; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 1b4348105..0d1bf2394 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -129,10 +129,10 @@ private: typedef ptr_vector exprs; public: - maxres(maxsat_context& c, unsigned index, - weights_t& ws, expr_ref_vector const& soft, + maxres(maxsat_context& c, unsigned index, + vector& soft, strategy_t st): - maxsmt_solver_base(c, ws, soft), + maxsmt_solver_base(c, soft), m_index(index), m_B(m), m_asms(m), m_defs(m), m_new_core(m), @@ -875,17 +875,10 @@ public: } lbool init_local() { - m_lower.reset(); m_trail.reset(); lbool is_sat = l_true; - obj_map new_soft; - is_sat = find_mutexes(new_soft); - if (is_sat != l_true) { - return is_sat; - } - for (auto const& kv : new_soft) { - add_soft(kv.m_key, kv.m_value); - } + for (auto const& [e, w, t] : m_soft) + add_soft(e, w); m_max_upper = m_upper; m_found_feasible_optimum = false; m_last_index = 0; @@ -953,12 +946,12 @@ public: }; opt::maxsmt_solver_base* opt::mk_maxres( - maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, id, ws, soft, maxres::s_primal); + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal); } opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( - maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, id, ws, soft, maxres::s_primal_dual); + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal_dual); } diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 85c83efba..25ef9bf05 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -21,9 +21,9 @@ Notes: namespace opt { - maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, vector& soft); - maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector& soft); }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index bf25f3f95..538ecf59b 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -28,6 +28,7 @@ Notes: #include "opt/wmax.h" #include "opt/opt_params.hpp" #include "opt/opt_context.h" +#include "opt/opt_preprocess.h" #include "smt/theory_wmaxsat.h" #include "smt/theory_pb.h" @@ -35,17 +36,15 @@ Notes: namespace opt { maxsmt_solver_base::maxsmt_solver_base( - maxsat_context& c, vector const& ws, expr_ref_vector const& softs): + maxsat_context& c, vector& s): m(c.get_manager()), m_c(c), + m_soft(s), m_assertions(m), m_trail(m) { c.get_base_model(m_model); SASSERT(m_model); updt_params(c.params()); - for (unsigned i = 0; i < ws.size(); ++i) { - m_soft.push_back(soft(expr_ref(softs.get(i), m), ws[i], false)); - } } void maxsmt_solver_base::updt_params(params_ref& p) { @@ -88,14 +87,22 @@ namespace opt { m_upper.reset(); for (soft& s : m_soft) { s.set_value(m.is_true(s.s)); - if (!s.is_true()) m_upper += s.weight; + if (!s.is_true()) + m_upper += s.weight; } + + preprocess pp(s()); + rational lower(0); + bool r = pp(m_soft, lower); + + if (lower != 0) + m_adjust_value.set_offset(lower + m_adjust_value.get_offset()); TRACE("opt", tout << "upper: " << m_upper << " assignments: "; for (soft& s : m_soft) tout << (s.is_true()?"T":"F"); tout << "\n";); - return true; + return r; } void maxsmt_solver_base::set_mus(bool f) { @@ -165,74 +172,9 @@ namespace opt { verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } - lbool maxsmt_solver_base::find_mutexes(obj_map& new_soft) { - m_lower.reset(); - expr_ref_vector fmls(m); - for (soft& s : m_soft) { - new_soft.insert(s.s, s.weight); - fmls.push_back(s.s); - } - vector mutexes; - lbool is_sat = s().find_mutexes(fmls, mutexes); - if (is_sat != l_true) { - return is_sat; - } - for (auto& mux : mutexes) { - process_mutex(mux, new_soft); - } - return l_true; - } - - struct maxsmt_compare_soft { - obj_map const& m_soft; - maxsmt_compare_soft(obj_map const& soft): m_soft(soft) {} - bool operator()(expr* a, expr* b) const { - return m_soft.find(a) > m_soft.find(b); - } - }; - - void maxsmt_solver_base::process_mutex(expr_ref_vector& mutex, obj_map& new_soft) { - TRACE("opt", - for (expr* e : mutex) { - tout << mk_pp(e, m) << " |-> " << new_soft.find(e) << "\n"; - }); - if (mutex.size() <= 1) { - return; - } - maxsmt_compare_soft cmp(new_soft); - ptr_vector _mutex(mutex.size(), mutex.data()); - std::sort(_mutex.begin(), _mutex.end(), cmp); - mutex.reset(); - mutex.append(_mutex.size(), _mutex.data()); - - rational weight(0), sum1(0), sum2(0); - vector weights; - for (expr* e : mutex) { - rational w = new_soft.find(e); - weights.push_back(w); - sum1 += w; - new_soft.remove(e); - } - for (unsigned i = mutex.size(); i-- > 0; ) { - expr_ref soft(m.mk_or(i+1, mutex.data()), m); - m_trail.push_back(soft); - rational w = weights[i]; - weight = w - weight; - m_lower += weight*rational(i); - IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";); - sum2 += weight*rational(i+1); - new_soft.insert(soft, weight); - for (; i > 0 && weights[i-1] == w; --i) {} - weight = w; - } - SASSERT(sum1 == sum2); - } - - maxsmt::maxsmt(maxsat_context& c, unsigned index): - m(c.get_manager()), m_c(c), m_index(index), - m_soft_constraints(m), m_answer(m) {} + m(c.get_manager()), m_c(c), m_index(index), m_answer(m) {} lbool maxsmt::operator()() { lbool is_sat = l_undef; @@ -241,25 +183,25 @@ namespace opt { symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); TRACE("opt_verbose", s().display(tout << "maxsmt\n") << "\n";); - if (optp.maxlex_enable() && is_maxlex(m_weights)) { - m_msolver = mk_maxlex(m_c, m_index, m_weights, m_soft_constraints); + if (optp.maxlex_enable() && is_maxlex(m_soft)) { + m_msolver = mk_maxlex(m_c, m_index, m_soft); } - else if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { - m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); + else if (m_soft.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { + m_msolver = mk_maxres(m_c, m_index, m_soft); } else if (maxsat_engine == symbol("pd-maxres")) { - m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints); + m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); } else if (maxsat_engine == symbol("wmax")) { - m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); + m_msolver = mk_wmax(m_c, m_soft); } else if (maxsat_engine == symbol("sortmax")) { - m_msolver = mk_sortmax(m_c, m_weights, m_soft_constraints); + m_msolver = mk_sortmax(m_c, m_soft); } else { auto str = maxsat_engine.str(); warning_msg("solver %s is not recognized, using default 'maxres'", str.c_str()); - m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); + m_msolver = mk_maxres(m_c, m_index, m_soft); } if (m_msolver) { @@ -360,39 +302,32 @@ namespace opt { SASSERT(w.is_pos()); unsigned index = 0; if (m_soft_constraint_index.find(f, index)) { - m_weights[index] += w; + m_soft[index].weight += w; } else { - m_soft_constraint_index.insert(f, m_weights.size()); - m_soft_constraints.push_back(f); - m_weights.push_back(w); + m_soft_constraint_index.insert(f, m_soft.size()); + m_soft.push_back(soft(expr_ref(f, m), w, false)); } m_upper += w; } struct cmp_first { bool operator()(std::pair const& x, std::pair const& y) const { - return x.first < y.first; + return x.second < y.second; } }; void maxsmt::display_answer(std::ostream& out) const { - vector> sorted_weights; - unsigned n = m_weights.size(); - for (unsigned i = 0; i < n; ++i) { - sorted_weights.push_back(std::make_pair(i, m_weights[i])); - } - std::sort(sorted_weights.begin(), sorted_weights.end(), cmp_first()); - sorted_weights.reverse(); - for (unsigned i = 0; i < n; ++i) { - unsigned idx = sorted_weights[i].first; - expr* e = m_soft_constraints[idx]; + + unsigned idx = 0; + for (auto const & [_e, w, t] : m_soft) { + expr* e = _e.get(); bool is_not = m.is_not(e, e); - out << m_weights[idx] << ": " << mk_pp(e, m) + out << w << ": " << mk_pp(e, m) << ((is_not != get_assignment(idx))?" |-> true ":" |-> false ") << "\n"; - - } + ++idx; + } } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 5bf637dde..4029bb911 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -52,21 +52,23 @@ namespace opt { // --------------------------------------------- // base class with common utilities used // by maxsmt solvers - // + // + + struct soft { + expr_ref s; + rational weight; + lbool value; + void set_value(bool t) { value = t?l_true:l_undef; } + void set_value(lbool t) { value = t; } + bool is_true() const { return value == l_true; } + soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), value(t?l_true:l_undef) {} + }; + class maxsmt_solver_base : public maxsmt_solver { protected: - struct soft { - expr_ref s; - rational weight; - lbool value; - void set_value(bool t) { value = t?l_true:l_undef; } - void set_value(lbool t) { value = t; } - bool is_true() const { return value == l_true; } - soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), value(t?l_true:l_undef) {} - }; ast_manager& m; maxsat_context& m_c; - vector m_soft; + vector& m_soft; expr_ref_vector m_assertions; expr_ref_vector m_trail; rational m_lower; @@ -76,8 +78,8 @@ namespace opt { params_ref m_params; // config public: - maxsmt_solver_base(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); - + maxsmt_solver_base(maxsat_context& c, vector& soft); + ~maxsmt_solver_base() override {} rational get_lower() const override { return m_lower; } rational get_upper() const override { return m_upper; } @@ -102,8 +104,6 @@ namespace opt { smt::theory_wmaxsat& operator()(); }; - lbool find_mutexes(obj_map& new_soft); - void reset_upper(); @@ -111,9 +111,6 @@ namespace opt { void enable_sls(bool force); void trace_bounds(char const* solver); - void process_mutex(expr_ref_vector& mutex, obj_map& new_soft); - - }; /** @@ -126,10 +123,9 @@ namespace opt { maxsat_context& m_c; unsigned m_index; scoped_ptr m_msolver; - expr_ref_vector m_soft_constraints; + vector m_soft; obj_map m_soft_constraint_index; expr_ref_vector m_answer; - vector m_weights; rational m_lower; rational m_upper; adjust_value m_adjust_value; @@ -142,9 +138,9 @@ namespace opt { void updt_params(params_ref& p); void add(expr* f, rational const& w); void set_adjust_value(adjust_value& adj); - unsigned size() const { return m_soft_constraints.size(); } - expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; } - rational weight(unsigned idx) const { return m_weights[idx]; } + unsigned size() const { return m_soft.size(); } + expr* operator[](unsigned idx) const { return m_soft[idx].s; } + rational weight(unsigned idx) const { return m_soft[idx].weight; } void commit_assignment(); rational get_lower() const; rational get_upper() const; diff --git a/src/opt/opt_mux.h b/src/opt/opt_mux.h new file mode 100644 index 000000000..b093026f0 --- /dev/null +++ b/src/opt/opt_mux.h @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + opt_mux.h + +Abstract: + + Find mutexes - at most 1 constraints and modify soft constraints and bounds. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-11 + +--*/ + +#pragma once + +#include "opt/maxsmt.h" + +namespace opt { + + class mux { + ast_manager& m; + solver& s; + + public: + mux(solver& s); + lbool operator()(vector& soft, rational& bound); + }; +}; diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp new file mode 100644 index 000000000..f65d5d09b --- /dev/null +++ b/src/opt/opt_preprocess.cpp @@ -0,0 +1,102 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + opt_preprocess.cpp + +Abstract: + + Pre-processing for MaxSMT + + Find mutexes - at most 1 constraints and modify soft constraints and bounds. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-11 + +--*/ + +#pragma once + +#include "opt/opt_preprocess.h" + +namespace opt { + + bool preprocess::find_mutexes(vector& softs, rational& lower) { + expr_ref_vector fmls(m); + obj_map new_soft; + for (soft& sf : softs) { + m_trail.push_back(sf.s); + if (new_soft.contains(sf.s)) + new_soft[sf.s] += sf.weight; + else + new_soft.insert(sf.s, sf.weight); + fmls.push_back(sf.s); + } + vector mutexes; + lbool is_sat = s.find_mutexes(fmls, mutexes); + if (is_sat == l_false) + return true; + if (is_sat == l_undef) + return false; + for (auto& mux : mutexes) + process_mutex(mux, new_soft, lower); + softs.reset(); + for (auto const& [k, v] : new_soft) + softs.push_back(soft(expr_ref(k, m), v, false)); + m_trail.reset(); + return true; + } + + struct maxsmt_compare_soft { + obj_map const& m_soft; + maxsmt_compare_soft(obj_map const& soft): m_soft(soft) {} + bool operator()(expr* a, expr* b) const { + return m_soft.find(a) > m_soft.find(b); + } + }; + + void preprocess::process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower) { + TRACE("opt", + for (expr* e : mutex) { + tout << mk_pp(e, m) << " |-> " << new_soft.find(e) << "\n"; + }); + if (mutex.size() <= 1) + return; + + maxsmt_compare_soft cmp(new_soft); + ptr_vector _mutex(mutex.size(), mutex.data()); + std::sort(_mutex.begin(), _mutex.end(), cmp); + mutex.reset(); + mutex.append(_mutex.size(), _mutex.data()); + + rational weight(0), sum1(0), sum2(0); + vector weights; + for (expr* e : mutex) { + rational w = new_soft.find(e); + weights.push_back(w); + sum1 += w; + new_soft.remove(e); + } + for (unsigned i = mutex.size(); i-- > 0; ) { + expr_ref soft(m.mk_or(i+1, mutex.data()), m); + m_trail.push_back(soft); + rational w = weights[i]; + weight = w - weight; + lower += weight*rational(i); + IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";); + sum2 += weight*rational(i+1); + new_soft.insert(soft, weight); + for (; i > 0 && weights[i-1] == w; --i) {} + weight = w; + } + SASSERT(sum1 == sum2); + } + + preprocess::preprocess(solver& s): m(s.get_manager()), s(s), m_trail(m) {} + + bool preprocess::operator()(vector& soft, rational& lower) { + return find_mutexes(soft, lower); + } +}; diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h new file mode 100644 index 000000000..8918e5e89 --- /dev/null +++ b/src/opt/opt_preprocess.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2021 Microsoft Corporation + +Module Name: + + opt_preprocess.h + +Abstract: + + Pre-processing for MaxSMT + + Find mutexes - at most 1 constraints and modify soft constraints and bounds. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-04-11 + +--*/ + +#pragma once + +#include "opt/maxsmt.h" + +namespace opt { + + class preprocess { + ast_manager& m; + solver& s; + expr_ref_vector m_trail; + + bool find_mutexes(vector& softs, rational& lower); + void process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower); + + public: + preprocess(solver& s); + bool operator()(vector& soft, rational& lower); + }; +}; diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index c6a2f04a9..a6539e129 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -36,34 +36,27 @@ namespace opt { expr_ref_vector m_trail; func_decl_ref_vector m_fresh; ref m_filter; - sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {} + sortmax(maxsat_context& c, vector& s): + maxsmt_solver_base(c, s), m_sort(*this), m_trail(m), m_fresh(m) {} ~sortmax() override {} lbool operator()() override { - obj_map soft; - if (!init()) { - return l_false; - } - lbool is_sat = find_mutexes(soft); - if (is_sat != l_true) { - return is_sat; - } + if (!init()) + return l_undef; + + lbool is_sat = l_true; m_filter = alloc(generic_model_converter, m, "sortmax"); - rational offset = m_lower; - m_upper = offset; expr_ref_vector in(m); expr_ref tmp(m); ptr_vector out; - obj_map::iterator it = soft.begin(), end = soft.end(); - for (; it != end; ++it) { - if (!it->m_value.is_unsigned()) { + for (auto const & [e, w, t] : m_soft) { + if (!w.is_unsigned()) { throw default_exception("sortmax can only handle unsigned weights. Use a different heuristic."); } - unsigned n = it->m_value.get_unsigned(); + unsigned n = w.get_unsigned(); while (n > 0) { - in.push_back(it->m_key); + in.push_back(e); --n; } } @@ -71,19 +64,15 @@ namespace opt { // initialize sorting network outputs using the initial assignment. unsigned first = 0; - it = soft.begin(); - for (; it != end; ++it) { - if (m_model->is_true(it->m_key)) { - unsigned n = it->m_value.get_unsigned(); + for (auto const & [e, w, t] : m_soft) { + if (t == l_true) { + unsigned n = w.get_unsigned(); while (n > 0) { s().assert_expr(out[first]); ++first; --n; } } - else { - m_upper += it->m_value; - } } while (l_true == is_sat && first < out.size() && m_lower < m_upper) { trace_bounds("sortmax"); @@ -149,8 +138,8 @@ namespace opt { }; - maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(sortmax, c, ws, soft); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s) { + return alloc(sortmax, c, s); } } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 22a660799..812c8f954 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -44,8 +44,8 @@ namespace opt { } public: - wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), + wmax(maxsat_context& c, vector& s): + maxsmt_solver_base(c, s), m_trail(m), m_defs(m) {} @@ -54,22 +54,18 @@ namespace opt { lbool operator()() override { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); - obj_map soft; reset(); - lbool is_sat = find_mutexes(soft); - if (is_sat != l_true) { - return is_sat; - } - m_upper = m_lower; + if (init()) + return l_undef; + + lbool is_sat = l_true; + expr_ref_vector asms(m); vector cores; - for (auto const& kv : soft) { - assert_weighted(wth(), kv.m_key, kv.m_value); - if (!is_true(kv.m_key)) { - m_upper += kv.m_value; - } - } + for (auto const& [k, w, t] : m_soft) + assert_weighted(wth(), k, w); + wth().init_min_cost(m_upper - m_lower); trace_bounds("wmax"); @@ -308,8 +304,8 @@ namespace opt { }; - maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(wmax, c, ws, soft); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector & s) { + return alloc(wmax, c, s); } } diff --git a/src/opt/wmax.h b/src/opt/wmax.h index 6cc3ed46b..0a5167269 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -22,8 +22,8 @@ Notes: #include "opt/maxsmt.h" namespace opt { - maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector& s); - maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s); } diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 116621dcc..045b92c99 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -312,6 +312,7 @@ namespace euf { } } else if (m.is_distinct(e)) { + // TODO - add lazy case for large values of sz. expr_ref_vector eqs(m); unsigned sz = n->num_args(); for (unsigned i = 0; i < sz; ++i) { From ac55e29a56d78bc0bbba26c7346ba0f45431f99b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Apr 2022 22:23:42 +0200 Subject: [PATCH 238/258] disable propagation Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 19 +++++++++++-------- src/opt/maxsmt.h | 6 +++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 538ecf59b..dab9ae445 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -91,12 +91,15 @@ namespace opt { m_upper += s.weight; } + return true; + preprocess pp(s()); rational lower(0); bool r = pp(m_soft, lower); + if (lower != 0) - m_adjust_value.set_offset(lower + m_adjust_value.get_offset()); + m_adjust_value->set_offset(lower + m_adjust_value->get_offset()); TRACE("opt", tout << "upper: " << m_upper << " assignments: "; @@ -166,8 +169,8 @@ namespace opt { void maxsmt_solver_base::trace_bounds(char const * solver) { IF_VERBOSE(1, - rational l = m_adjust_value(m_lower); - rational u = m_adjust_value(m_upper); + rational l = (*m_adjust_value)(m_lower); + rational u = (*m_adjust_value)(m_upper); if (l > u) std::swap(l, u); verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } @@ -206,7 +209,7 @@ namespace opt { if (m_msolver) { m_msolver->updt_params(m_params); - m_msolver->set_adjust_value(m_adjust_value); + m_msolver->set_adjust_value(*m_adjust_value); is_sat = l_undef; try { is_sat = (*m_msolver)(); @@ -231,9 +234,9 @@ namespace opt { } void maxsmt::set_adjust_value(adjust_value& adj) { - m_adjust_value = adj; + m_adjust_value = &adj; if (m_msolver) { - m_msolver->set_adjust_value(m_adjust_value); + m_msolver->set_adjust_value(adj); } } @@ -265,7 +268,7 @@ namespace opt { rational q = m_msolver->get_lower(); if (q > r) r = q; } - return m_adjust_value(r); + return (*m_adjust_value)(r); } rational maxsmt::get_upper() const { @@ -274,7 +277,7 @@ namespace opt { rational q = m_msolver->get_upper(); if (q < r) r = q; } - return m_adjust_value(r); + return (*m_adjust_value)(r); } void maxsmt::update_lower(rational const& r) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 4029bb911..5a3dc4ca8 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -35,7 +35,7 @@ namespace opt { class maxsmt_solver { protected: - adjust_value m_adjust_value; + adjust_value* m_adjust_value = nullptr; public: virtual ~maxsmt_solver() {} virtual lbool operator()() = 0; @@ -45,7 +45,7 @@ namespace opt { virtual void collect_statistics(statistics& st) const = 0; virtual void get_model(model_ref& mdl, svector& labels) = 0; virtual void updt_params(params_ref& p) = 0; - void set_adjust_value(adjust_value& adj) { m_adjust_value = adj; } + void set_adjust_value(adjust_value& adj) { m_adjust_value = &adj; } }; @@ -128,7 +128,7 @@ namespace opt { expr_ref_vector m_answer; rational m_lower; rational m_upper; - adjust_value m_adjust_value; + adjust_value* m_adjust_value = nullptr; model_ref m_model; svector m_labels; params_ref m_params; From b264e6c2904456beae27ce19ec4997251034e42c Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Tue, 12 Apr 2022 12:29:53 +0200 Subject: [PATCH 239/258] Reverted reusing can_propagate (#5966) * Fixed registering expressions in push/pop * Reused existing function * Reverted reusing can_propagate --- src/smt/theory_user_propagator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index daded32c7..f783f22fb 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -133,7 +133,7 @@ final_check_status theory_user_propagator::final_check_eh() { } propagate(); // check if it became inconsistent or something new was propagated/registered - bool done = !can_propagate() && !ctx.inconsistent(); + bool done = (sz1 == m_prop.size()) && (sz2 == m_expr2var.size()) && !ctx.inconsistent(); return done ? FC_DONE : FC_CONTINUE; } From 032768b0fc2a6350950ac3065f50ca29eb5495f0 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Tue, 12 Apr 2022 23:29:36 -0700 Subject: [PATCH 240/258] setup.py: copy generated python files correctly (#5975) --- src/api/python/setup.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 1b455bb56..5309142f2 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -154,16 +154,10 @@ def _copy_bins(): _clean_bins() - python_dir = None - if RELEASE_DIR is not None: - python_dir = os.path.join(RELEASE_DIR, 'bin', 'python') - elif SRC_DIR == SRC_DIR_LOCAL: - python_dir = os.path.join(SRC_DIR, 'src', 'api', 'python') - if python_dir is not None: - py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3') - root_z3_dir = os.path.join(ROOT_DIR, 'z3') - shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir) - shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir) + py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3') + root_z3_dir = os.path.join(ROOT_DIR, 'z3') + shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir) + shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir) # STEP 2: Copy the shared library, the executable and the headers From 9834d7aae0faf2b1cc9b96c7c20b087f96374c51 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Tue, 12 Apr 2022 23:31:24 -0700 Subject: [PATCH 241/258] Setup.py fix dependencies (#5971) * Add wheel as build dependency * pyproject toml update --- src/api/python/pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/api/python/pyproject.toml diff --git a/src/api/python/pyproject.toml b/src/api/python/pyproject.toml new file mode 100644 index 000000000..ead8162b7 --- /dev/null +++ b/src/api/python/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=46.4.0", "wheel"] +build-backend = "setuptools.build_meta" From c0b455e01089fdafd2dadd5124d2080dff777823 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Tue, 12 Apr 2022 23:48:08 -0700 Subject: [PATCH 242/258] Add cmake setup.py build dep (#5972) * Add wheel as build dependency * Add cmake as a python build dependency * pyproject toml update Co-authored-by: Nikolaj Bjorner --- src/api/python/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/pyproject.toml b/src/api/python/pyproject.toml index ead8162b7..a9f2676a7 100644 --- a/src/api/python/pyproject.toml +++ b/src/api/python/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["setuptools>=46.4.0", "wheel"] +requires = ["setuptools>=46.4.0", "wheel", "cmake"] build-backend = "setuptools.build_meta" From c9fa00aec1442464c9cc2ab6f3d2e5c749232b6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 11:22:43 +0200 Subject: [PATCH 243/258] expose recursive functions with own op-code over API --- src/api/api_ast.cpp | 3 +++ src/api/z3_api.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 7ee95afc8..9f9039378 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1329,6 +1329,9 @@ extern "C" { } } + if (mk_c(c)->recfun().get_family_id() == _d->get_family_id()) + return Z3_OP_RECURSIVE; + return Z3_OP_UNINTERPRETED; Z3_CATCH_RETURN(Z3_OP_UNINTERPRETED); } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 8a610bc6d..1388d0ab1 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -996,6 +996,8 @@ typedef enum information is exposed. Tools may use the string representation of the function declaration to obtain more information. + - Z3_OP_RECURSIVE: function declared as recursive + - Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols. */ typedef enum { @@ -1320,6 +1322,7 @@ typedef enum { Z3_OP_FPA_BV2RM, Z3_OP_INTERNAL, + Z3_OP_RECURSIVE, Z3_OP_UNINTERPRETED } Z3_decl_kind; From 3f5eb7fcf29dad76498e560826f9474016358027 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 11:24:16 +0200 Subject: [PATCH 244/258] re-enable pre-process --- src/opt/maxlex.cpp | 2 +- src/opt/maxres.cpp | 4 +--- src/opt/maxsmt.cpp | 42 ++++++++++++++++++++--------------------- src/opt/maxsmt.h | 10 +++------- src/opt/opt_context.cpp | 40 +++++++++++++++++++++------------------ src/opt/opt_context.h | 9 +++++++-- src/opt/opt_solver.h | 1 + src/opt/sortmax.cpp | 8 ++++---- src/opt/wmax.cpp | 8 ++++---- src/opt/wmax.h | 4 ++-- 10 files changed, 66 insertions(+), 62 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 82eee6f5e..fa97359d0 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -186,7 +186,7 @@ namespace opt { public: maxlex(maxsat_context& c, unsigned id, vector& s): - maxsmt_solver_base(c, s), + maxsmt_solver_base(c, s, id), m(c.get_manager()), m_c(c) { // ensure that soft constraints are sorted with largest soft constraints first. diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 0d1bf2394..135e0f80e 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -95,7 +95,6 @@ private: expr_ref_vector const& soft() override { return i.m_asms; } }; - unsigned m_index; stats m_stats; expr_ref_vector m_B; expr_ref_vector m_asms; @@ -132,8 +131,7 @@ public: maxres(maxsat_context& c, unsigned index, vector& soft, strategy_t st): - maxsmt_solver_base(c, soft), - m_index(index), + maxsmt_solver_base(c, soft, index), m_B(m), m_asms(m), m_defs(m), m_new_core(m), m_mus(c.get_solver()), diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index dab9ae445..a3d5f2f45 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -35,10 +35,10 @@ Notes: namespace opt { - maxsmt_solver_base::maxsmt_solver_base( - maxsat_context& c, vector& s): + maxsmt_solver_base::maxsmt_solver_base(maxsat_context& c, vector& s, unsigned index): m(c.get_manager()), m_c(c), + m_index(index), m_soft(s), m_assertions(m), m_trail(m) { @@ -91,18 +91,17 @@ namespace opt { m_upper += s.weight; } - return true; + // return true; preprocess pp(s()); rational lower(0); bool r = pp(m_soft, lower); - - if (lower != 0) - m_adjust_value->set_offset(lower + m_adjust_value->get_offset()); + m_c.add_offset(m_index, lower); + m_upper -= lower; TRACE("opt", - tout << "upper: " << m_upper << " assignments: "; + tout << "lower " << lower << " upper: " << m_upper << " assignments: "; for (soft& s : m_soft) tout << (s.is_true()?"T":"F"); tout << "\n";); return r; @@ -169,8 +168,8 @@ namespace opt { void maxsmt_solver_base::trace_bounds(char const * solver) { IF_VERBOSE(1, - rational l = (*m_adjust_value)(m_lower); - rational u = (*m_adjust_value)(m_upper); + rational l = m_c.adjust(m_index, m_lower); + rational u = m_c.adjust(m_index, m_upper); if (l > u) std::swap(l, u); verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } @@ -196,10 +195,10 @@ namespace opt { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); } else if (maxsat_engine == symbol("wmax")) { - m_msolver = mk_wmax(m_c, m_soft); + m_msolver = mk_wmax(m_c, m_soft, m_index); } else if (maxsat_engine == symbol("sortmax")) { - m_msolver = mk_sortmax(m_c, m_soft); + m_msolver = mk_sortmax(m_c, m_soft, m_index); } else { auto str = maxsat_engine.str(); @@ -209,7 +208,6 @@ namespace opt { if (m_msolver) { m_msolver->updt_params(m_params); - m_msolver->set_adjust_value(*m_adjust_value); is_sat = l_undef; try { is_sat = (*m_msolver)(); @@ -233,13 +231,6 @@ namespace opt { return is_sat; } - void maxsmt::set_adjust_value(adjust_value& adj) { - m_adjust_value = &adj; - if (m_msolver) { - m_msolver->set_adjust_value(adj); - } - } - void maxsmt::reset_upper() { if (m_msolver) { m_msolver->reset_upper(); @@ -268,7 +259,7 @@ namespace opt { rational q = m_msolver->get_lower(); if (q > r) r = q; } - return (*m_adjust_value)(r); + return m_c.adjust(m_index, r); } rational maxsmt::get_upper() const { @@ -277,7 +268,7 @@ namespace opt { rational q = m_msolver->get_upper(); if (q < r) r = q; } - return (*m_adjust_value)(r); + return m_c.adjust(m_index, r); } void maxsmt::update_lower(rational const& r) { @@ -370,6 +361,7 @@ namespace opt { model_ref m_model; ref m_fm; symbol m_maxsat_engine; + vector m_offsets; public: solver_maxsat_context(params_ref& p, solver* s, model * m): m_params(p), @@ -394,6 +386,14 @@ namespace opt { bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; }; void set_model(model_ref& _m) override { m_model = _m; } void model_updated(model* mdl) override { } // no-op + rational adjust(unsigned id, rational const& r) override { + m_offsets.reserve(id+1); + return r + m_offsets[id]; + } + void add_offset(unsigned id, rational const& r) override { + m_offsets.reserve(id+1); + m_offsets[id] += r; + } }; lbool maxsmt_wrapper::operator()(vector>& soft) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 5a3dc4ca8..b0ae5eeb1 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -34,8 +34,6 @@ namespace opt { class maxsat_context; class maxsmt_solver { - protected: - adjust_value* m_adjust_value = nullptr; public: virtual ~maxsmt_solver() {} virtual lbool operator()() = 0; @@ -45,7 +43,6 @@ namespace opt { virtual void collect_statistics(statistics& st) const = 0; virtual void get_model(model_ref& mdl, svector& labels) = 0; virtual void updt_params(params_ref& p) = 0; - void set_adjust_value(adjust_value& adj) { m_adjust_value = &adj; } }; @@ -67,7 +64,8 @@ namespace opt { class maxsmt_solver_base : public maxsmt_solver { protected: ast_manager& m; - maxsat_context& m_c; + maxsat_context& m_c; + unsigned m_index; vector& m_soft; expr_ref_vector m_assertions; expr_ref_vector m_trail; @@ -78,7 +76,7 @@ namespace opt { params_ref m_params; // config public: - maxsmt_solver_base(maxsat_context& c, vector& soft); + maxsmt_solver_base(maxsat_context& c, vector& soft, unsigned index); ~maxsmt_solver_base() override {} rational get_lower() const override { return m_lower; } @@ -128,7 +126,6 @@ namespace opt { expr_ref_vector m_answer; rational m_lower; rational m_upper; - adjust_value* m_adjust_value = nullptr; model_ref m_model; svector m_labels; params_ref m_params; @@ -137,7 +134,6 @@ namespace opt { lbool operator()(); void updt_params(params_ref& p); void add(expr* f, rational const& w); - void set_adjust_value(adjust_value& adj); unsigned size() const { return m_soft.size(); } expr* operator[](unsigned idx) const { return m_soft[idx].s; } rational weight(unsigned idx) const { return m_soft[idx].weight; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8848b61c9..25982e89e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -398,7 +398,7 @@ namespace opt { } void context::set_model(model_ref& m) { - m_model = m; + m_model = m; opt_params optp(m_params); if (optp.dump_models() && m) { model_ref md = m->copy(); @@ -930,7 +930,8 @@ namespace opt { bool context::is_maxsat(expr* fml, expr_ref_vector& terms, vector& weights, rational& offset, bool& neg, symbol& id, expr_ref& orig_term, unsigned& index) { - if (!is_app(fml)) return false; + if (!is_app(fml)) + return false; neg = false; orig_term = nullptr; index = 0; @@ -1105,8 +1106,7 @@ namespace opt { obj.m_weights.append(weights); obj.m_adjust_value.set_offset(offset); obj.m_adjust_value.set_negate(neg); - m_maxsmts.find(id)->set_adjust_value(obj.m_adjust_value); - TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n"; + TRACE("opt", tout << "maxsat: " << neg << " " << id << " offset: " << offset << "\n"; tout << terms << "\n";); } else if (is_maximize(fml, tr, orig_term, index)) { @@ -1158,7 +1158,14 @@ namespace opt { #endif } + rational context::adjust(unsigned id, rational const& v) { + return m_objectives[id].m_adjust_value(v); + } + void context::add_offset(unsigned id, rational const& o) { + m_objectives[id].m_adjust_value.add_offset(o); + } + bool context::verify_model(unsigned index, model* md, rational const& _v) { rational r; app_ref term = m_objectives[index].m_term; @@ -1341,24 +1348,21 @@ namespace opt { break; } case O_MAXSMT: { - bool ok = true; - for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { + for (unsigned j = 0; j < obj.m_terms.size(); ++j) { val = (*m_model)(obj.m_terms[j]); TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";); - if (!m.is_true(val)) { + if (!m.is_true(val)) r += obj.m_weights[j]; - } } - if (ok) { - maxsmt& ms = *m_maxsmts.find(obj.m_id); - if (is_lower) { - ms.update_upper(r); - TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";); - } - else { - ms.update_lower(r); - TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";); - } + + maxsmt& ms = *m_maxsmts.find(obj.m_id); + if (is_lower) { + ms.update_upper(r); + TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";); + } + else { + ms.update_lower(r); + TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";); } break; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 1e950174a..c02689a38 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -57,6 +57,8 @@ namespace opt { virtual smt::context& smt_context() = 0; // access SMT context for SMT based MaxSMT solver (wmax requires SMT core) virtual unsigned num_objectives() = 0; virtual bool verify_model(unsigned id, model* mdl, rational const& v) = 0; + virtual rational adjust(unsigned id, rational const& v) = 0; + virtual void add_offset(unsigned id, rational const& o) = 0; virtual void set_model(model_ref& _m) = 0; virtual void model_updated(model* mdl) = 0; }; @@ -93,7 +95,7 @@ namespace opt { app_ref m_term; // for maximize, minimize term expr_ref_vector m_terms; // for maxsmt vector m_weights; // for maxsmt - adjust_value m_adjust_value; + adjust_value m_adjust_value; symbol m_id; // for maxsmt unsigned m_index; // for maximize/minimize index @@ -269,11 +271,14 @@ namespace opt { void model_updated(model* mdl) override; + rational adjust(unsigned id, rational const& v) override; + + void add_offset(unsigned id, rational const& o) override; + void register_on_model(on_model_t& ctx, std::function& on_model) { m_on_model_ctx = ctx; m_on_model_eh = on_model; } - void collect_timer_stats(statistics& st) const { if (m_time != 0) diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index caac008fd..47fe86f94 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -48,6 +48,7 @@ namespace opt { void set_offset(rational const& o) { m_offset = o; } void set_negate(bool neg) { m_negate = neg; } rational const& get_offset() const { return m_offset; } + void add_offset(rational const& o) { if (m_negate) m_offset -= o; else m_offset += o; } bool get_negate() { return m_negate; } inf_eps operator()(inf_eps const& r) const { inf_eps result = r; diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index a6539e129..962369bf2 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -36,8 +36,8 @@ namespace opt { expr_ref_vector m_trail; func_decl_ref_vector m_fresh; ref m_filter; - sortmax(maxsat_context& c, vector& s): - maxsmt_solver_base(c, s), m_sort(*this), m_trail(m), m_fresh(m) {} + sortmax(maxsat_context& c, vector& s, unsigned index): + maxsmt_solver_base(c, s, index), m_sort(*this), m_trail(m), m_fresh(m) {} ~sortmax() override {} @@ -138,8 +138,8 @@ namespace opt { }; - maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s) { - return alloc(sortmax, c, s); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s, unsigned index) { + return alloc(sortmax, c, s, index); } } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 812c8f954..1fbd26cb8 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -44,8 +44,8 @@ namespace opt { } public: - wmax(maxsat_context& c, vector& s): - maxsmt_solver_base(c, s), + wmax(maxsat_context& c, vector& s, unsigned index): + maxsmt_solver_base(c, s, index), m_trail(m), m_defs(m) {} @@ -304,8 +304,8 @@ namespace opt { }; - maxsmt_solver_base* mk_wmax(maxsat_context& c, vector & s) { - return alloc(wmax, c, s); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector & s, unsigned index) { + return alloc(wmax, c, s, index); } } diff --git a/src/opt/wmax.h b/src/opt/wmax.h index 0a5167269..7f5b26ac6 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -22,8 +22,8 @@ Notes: #include "opt/maxsmt.h" namespace opt { - maxsmt_solver_base* mk_wmax(maxsat_context& c, vector& s); + maxsmt_solver_base* mk_wmax(maxsat_context& c, vector& s, unsigned index); - maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, vector& s, unsigned index); } From ddbe17d581d9835f9bc57079383eefce2b841162 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 16:08:54 +0200 Subject: [PATCH 245/258] #5965 define the is_bool on ArithSortRef --- src/api/python/z3/z3.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index d3d6067c3..223b3e038 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2279,6 +2279,9 @@ class ArithSortRef(SortRef): """ return self.kind() == Z3_INT_SORT + def is_bool(self): + return False + def subsort(self, other): """Return `True` if `self` is a subsort of `other`.""" return self.is_int() and is_arith_sort(other) and other.is_real() From 7d47e45c6b734ce89b511817c3589a382f241878 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Fri, 15 Apr 2022 00:57:51 -0700 Subject: [PATCH 246/258] Add a hacky patch so that Z3 on M1 hardware can link to libs properly (#5974) * Add a hacky patch so that Z3 on M1 hardware can link to libs properly * Update setup.py Co-authored-by: Nikolaj Bjorner --- src/api/python/setup.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 5309142f2..6179422df 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -178,6 +178,20 @@ def _copy_bins(): continue shutil.copy(os.path.join(header_dir, fname), os.path.join(HEADERS_DIR, fname)) + # This hack lets z3 installed libs link on M1 macs; it is a hack, not a proper fix + # @TODO: Linked issue: https://github.com/Z3Prover/z3/issues/5926 + major_minor = '.'.join(_z3_version().split('.')[:2]) + link_name = None + if BUILD_PLATFORM in ('win32', 'cygwin', 'win'): + pass # TODO: When windows VMs work on M1, fill this in + elif BUILD_PLATFORM in ('darwin', 'osx'): + split = LIBRARY_FILE.split('.') + link_name = split[0] + '.' + major_minor + '.' + split[1] + else: + link_name = LIBRARY_FILE + '.' + major_minor + if link_name: + os.symlink(LIBRARY_FILE, os.path.join(LIBS_DIR, link_name), True) + def _copy_sources(): """ Prepare for a source distribution by assembling a minimal set of source files needed @@ -273,10 +287,10 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: osver = RELEASE_METADATA[3] if osver.count('.') > 1: osver = '.'.join(osver.split('.')[:2]) - if arch == 'x64': + if arch == 'x64': plat_name ='macosx_%s_x86_64' % osver.replace('.', '_') elif arch == 'arm64': - plat_name ='macosx_%s_arm64' % osver.replace('.', '_') + plat_name ='macosx_%s_arm64' % osver.replace('.', '_') else: raise Exception(f"idk how os {distos} {osver} works. what goes here?") else: @@ -287,7 +301,6 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: sys.argv.insert(idx + 1, plat_name) sys.argv.insert(idx + 2, '--universal') # supports py2+py3. if --plat-name is not specified this will also mean that the package can be installed on any machine regardless of architecture, so watch out! - setup( name='z3-solver', version=_z3_version(), From a634876180430cf110e9d11691f816cd1f7b96dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Apr 2022 18:00:02 +0200 Subject: [PATCH 247/258] sort muxes --- src/cmd_context/eval_cmd.cpp | 2 ++ src/sat/sat_solver.cpp | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index 8819eb584..70a48da5f 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -57,6 +57,8 @@ public: void execute(cmd_context & ctx) override { model_ref md; + if (ctx.ignore_check()) + return; if (!ctx.is_model_available(md)) throw cmd_exception("model is not available"); if (!m_target) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4a254ac06..12dfb72b5 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4192,17 +4192,19 @@ namespace sat { m_ext->find_mutexes(_lits, mutexes); } unsigned_vector ps; - for (literal lit : _lits) { + for (literal lit : _lits) ps.push_back(lit.index()); - } mc.cliques(ps, _mutexes); + vector> sorted; for (auto const& mux : _mutexes) { literal_vector clique; - for (auto const& idx : mux) { + sorted.reserve(mux.size() + 1); + for (auto const& idx : mux) clique.push_back(to_literal(idx)); - } - mutexes.push_back(clique); + sorted[mux.size()].push_back(clique); } + for (unsigned i = sorted.size(); i-- > 0; ) + mutexes.append(sorted[i]); return l_true; } From 3cc9d7f4438ffb56bb909c8bed8a84c133acede2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 12:55:17 +0200 Subject: [PATCH 248/258] improve pre-processing --- src/api/api_solver.cpp | 2 +- src/muz/spacer/spacer_iuc_solver.h | 2 +- src/opt/opt_preprocess.cpp | 15 ++- src/opt/opt_preprocess.h | 1 + src/opt/opt_solver.h | 2 +- src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 8 +- src/sat/smt/atom2bool_var.cpp | 8 +- src/smt/smt_context.cpp | 23 ++-- src/smt/smt_context.h | 2 +- src/smt/smt_kernel.cpp | 4 +- src/smt/smt_kernel.h | 2 +- src/smt/smt_solver.cpp | 4 +- src/solver/combined_solver.cpp | 6 +- src/solver/solver.h | 2 +- src/solver/solver_pool.cpp | 4 +- src/solver/tactic2solver.cpp | 2 +- .../fd_solver/bounded_int2bv_solver.cpp | 4 +- src/tactic/fd_solver/enum2bv_solver.cpp | 4 +- src/tactic/fd_solver/pb2bv_solver.cpp | 4 +- src/tactic/fd_solver/smtfd_solver.cpp | 4 +- src/util/max_cliques.h | 122 +++++++++++++----- 22 files changed, 147 insertions(+), 80 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 948064af6..c9eda8712 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -564,7 +564,7 @@ extern "C" { init_solver(c, s); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); - expr_ref_vector trail = to_solver_ref(s)->get_trail(); + expr_ref_vector trail = to_solver_ref(s)->get_trail(UINT_MAX); for (expr* f : trail) { v->m_ast_vector.push_back(f); } diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index fa9f76311..739588c6b 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -126,7 +126,7 @@ public: void move_to_front(expr* e) override { m_solver.move_to_front(e); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver.get_levels(vars, depth); } - expr_ref_vector get_trail() override { return m_solver.get_trail(); } + expr_ref_vector get_trail(unsigned max_level) override { return m_solver.get_trail(max_level); } void push() override; void pop(unsigned n) override; diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index f65d5d09b..6cbc8b1b9 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -23,10 +23,9 @@ Author: namespace opt { - bool preprocess::find_mutexes(vector& softs, rational& lower) { - expr_ref_vector fmls(m); + obj_map preprocess::soft2map(vector const& softs, expr_ref_vector& fmls) { obj_map new_soft; - for (soft& sf : softs) { + for (soft const& sf : softs) { m_trail.push_back(sf.s); if (new_soft.contains(sf.s)) new_soft[sf.s] += sf.weight; @@ -34,6 +33,12 @@ namespace opt { new_soft.insert(sf.s, sf.weight); fmls.push_back(sf.s); } + return new_soft; + } + + bool preprocess::find_mutexes(vector& softs, rational& lower) { + expr_ref_vector fmls(m); + obj_map new_soft = soft2map(softs, fmls); vector mutexes; lbool is_sat = s.find_mutexes(fmls, mutexes); if (is_sat == l_false) @@ -97,6 +102,8 @@ namespace opt { preprocess::preprocess(solver& s): m(s.get_manager()), s(s), m_trail(m) {} bool preprocess::operator()(vector& soft, rational& lower) { - return find_mutexes(soft, lower); + if (!find_mutexes(soft, lower)) + return false; + return true; } }; diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h index 8918e5e89..f5f1c9db6 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -28,6 +28,7 @@ namespace opt { solver& s; expr_ref_vector m_trail; + obj_map soft2map(vector const& softs, expr_ref_vector& fmls); bool find_mutexes(vector& softs, rational& lower); void process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 47fe86f94..e71287400 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,7 +108,7 @@ namespace opt { lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; lbool preferred_sat(expr_ref_vector const& asms, vector& cores) override; void get_levels(ptr_vector const& vars, unsigned_vector& depth) override; - expr_ref_vector get_trail() override { return m_context.get_trail(); } + expr_ref_vector get_trail(unsigned max_level) override { return m_context.get_trail(max_level); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void set_phase(expr* e) override { m_context.set_phase(e); } phase* get_phase() override { return m_context.get_phase(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 12dfb72b5..4f5c9ca8d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4194,7 +4194,7 @@ namespace sat { unsigned_vector ps; for (literal lit : _lits) ps.push_back(lit.index()); - mc.cliques(ps, _mutexes); + mc.cliques2(ps, _mutexes); vector> sorted; for (auto const& mux : _mutexes) { literal_vector clique; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 61dc53cd8..af0d9dd1b 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -390,7 +390,7 @@ public: } } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { expr_ref_vector result(m); unsigned sz = m_solver.trail_size(); expr_ref_vector lit2expr(m); @@ -398,7 +398,11 @@ public: m_map.mk_inv(lit2expr); for (unsigned i = 0; i < sz; ++i) { sat::literal lit = m_solver.trail_literal(i); - result.push_back(lit2expr[lit.index()].get()); + if (m_solver.lvl(lit) > max_level) + continue; + expr_ref e(lit2expr.get(lit.index()), m); + if (e) + result.push_back(e); } return result; } diff --git a/src/sat/smt/atom2bool_var.cpp b/src/sat/smt/atom2bool_var.cpp index 996e8e5e9..b12f51fb0 100644 --- a/src/sat/smt/atom2bool_var.cpp +++ b/src/sat/smt/atom2bool_var.cpp @@ -41,12 +41,12 @@ void atom2bool_var::mk_var_inv(expr_ref_vector & var2expr) const { sat::bool_var atom2bool_var::to_bool_var(expr * n) const { unsigned idx = m_id2map.get(n->get_id(), UINT_MAX); - if (idx == UINT_MAX) { + if (idx == UINT_MAX) return sat::null_bool_var; - } - else { + else if (idx >= m_mapping.size()) + return sat::null_bool_var; + else return m_mapping[idx].m_value; - } } struct collect_boolean_interface_proc { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 377ad1f2b..a9b44ab3c 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4612,9 +4612,15 @@ namespace smt { } } - expr_ref_vector context::get_trail() { + expr_ref_vector context::get_trail(unsigned max_level) { expr_ref_vector result(get_manager()); - get_assignments(result); + for (literal lit : m_assigned_literals) { + if (get_assign_level(lit) > max_level + m_base_lvl) + continue; + expr_ref e(m); + literal2expr(lit, e); + result.push_back(std::move(e)); + } return result; } @@ -4622,15 +4628,10 @@ namespace smt { expr_mark visited; for (expr* fml : result) visited.mark(fml); - for (literal lit : m_assigned_literals) { - if (get_assign_level(lit) > m_base_lvl) - break; - expr_ref e(m); - literal2expr(lit, e); - if (visited.is_marked(e)) - continue; - result.push_back(std::move(e)); - } + expr_ref_vector trail = get_trail(0); + for (expr* t : trail) + if (!visited.is_marked(t)) + result.push_back(t); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index ac2b0cfc8..637c2171b 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1667,7 +1667,7 @@ namespace smt { void get_levels(ptr_vector const& vars, unsigned_vector& depth); - expr_ref_vector get_trail(); + expr_ref_vector get_trail(unsigned max_level); void get_model(model_ref & m); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 87e5fd36d..2d082170c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -248,8 +248,8 @@ namespace smt { m_imp->m_kernel.get_levels(vars, depth); } - expr_ref_vector kernel::get_trail() { - return m_imp->m_kernel.get_trail(); + expr_ref_vector kernel::get_trail(unsigned max_level) { + return m_imp->m_kernel.get_trail(max_level); } void kernel::user_propagate_init( diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 77ad2559c..068bd1b52 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -248,7 +248,7 @@ namespace smt { /** \brief retrieve trail of assignment stack. */ - expr_ref_vector get_trail(); + expr_ref_vector get_trail(unsigned max_level); /** \brief (For debubbing purposes) Prints the state of the kernel diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ad67c19d1..344cf9e6f 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -208,8 +208,8 @@ namespace { m_context.get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_context.get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_context.get_trail(max_level); } void user_propagate_init( diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index b95d2d7f8..bfe495b6e 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -311,11 +311,11 @@ public: m_solver2->get_levels(vars, depth); } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { if (m_use_solver1_results) - return m_solver1->get_trail(); + return m_solver1->get_trail(max_level); else - return m_solver2->get_trail(); + return m_solver2->get_trail(max_level); } proof * get_proof() override { diff --git a/src/solver/solver.h b/src/solver/solver.h index 13692c857..dde4ccbe0 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -265,7 +265,7 @@ public: expr_ref_vector get_non_units(); - virtual expr_ref_vector get_trail() = 0; // { return expr_ref_vector(get_manager()); } + virtual expr_ref_vector get_trail(unsigned max_level) = 0; // { return expr_ref_vector(get_manager()); } virtual void get_levels(ptr_vector const& vars, unsigned_vector& depth) = 0; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 9e897208f..bbc46c9c8 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -127,8 +127,8 @@ public: m_base->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_base->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_base->get_trail(max_level); } lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index a2909fd7b..e8a30a009 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -134,7 +134,7 @@ public: throw default_exception("cannot retrieve depth from solvers created using tactics"); } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { throw default_exception("cannot retrieve trail from solvers created using tactics"); } }; diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index e907abc72..bc05a3328 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -165,8 +165,8 @@ public: void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_solver->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_solver->get_trail(max_level); } model_converter* external_model_converter() const { diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index 80e265676..cb136ad9f 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -189,8 +189,8 @@ public: m_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_solver->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_solver->get_trail(max_level); } unsigned get_num_assertions() const override { diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index f5d493af6..cd19b0dca 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -105,8 +105,8 @@ public: m_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { - return m_solver->get_trail(); + expr_ref_vector get_trail(unsigned max_level) override { + return m_solver->get_trail(max_level); } model_converter* external_model_converter() const{ diff --git a/src/tactic/fd_solver/smtfd_solver.cpp b/src/tactic/fd_solver/smtfd_solver.cpp index c5d67506e..32f9df9af 100644 --- a/src/tactic/fd_solver/smtfd_solver.cpp +++ b/src/tactic/fd_solver/smtfd_solver.cpp @@ -2098,9 +2098,9 @@ namespace smtfd { m_fd_sat_solver->get_levels(vars, depth); } - expr_ref_vector get_trail() override { + expr_ref_vector get_trail(unsigned max_level) override { init(); - return m_fd_sat_solver->get_trail(); + return m_fd_sat_solver->get_trail(max_level); } unsigned get_num_assertions() const override { diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 64a718bd1..ad6bc0219 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -20,6 +20,7 @@ Notes: #include "util/vector.h" #include "util/uint_set.h" +#include "util/heap.h" template @@ -43,12 +44,9 @@ class max_cliques : public T { m_seen1.insert(p); if (m_seen2.contains(p)) { unsigned_vector const& tc = m_tc[p]; - for (unsigned j = 0; j < tc.size(); ++j) { - unsigned np = tc[j]; - if (goal.contains(np)) { + for (unsigned np : tc) + if (goal.contains(np)) reachable.insert(np); - } - } } else { unsigned np = negate(p); @@ -61,29 +59,30 @@ class max_cliques : public T { for (unsigned i = m_todo.size(); i > 0; ) { --i; p = m_todo[i]; - if (m_seen2.contains(p)) { + if (m_seen2.contains(p)) continue; - } m_seen2.insert(p); unsigned np = negate(p); unsigned_vector& tc = m_tc[p]; - if (goal.contains(np)) { + if (goal.contains(np)) tc.push_back(np); - } - else { - unsigned_vector const& succ = next(np); - for (unsigned j = 0; j < succ.size(); ++j) { - tc.append(m_tc[succ[j]]); - } - } + else + for (unsigned s : next(np)) + tc.append(m_tc[s]); } } - - - - unsigned_vector const& next(unsigned vertex) const { return m_next[vertex]; } + + void init(unsigned_vector const& ps) { + unsigned max = 0; + for (unsigned p : ps) { + unsigned np = negate(p); + max = std::max(max, std::max(np, p) + 1); + } + m_next.reserve(max); + m_tc.reserve(m_next.size()); + } public: void add_edge(unsigned src, unsigned dst) { @@ -94,20 +93,11 @@ public: } void cliques(unsigned_vector const& ps, vector& cliques) { - unsigned max = 0; - unsigned num_ps = ps.size(); - for (unsigned i = 0; i < num_ps; ++i) { - unsigned p = ps[i]; - unsigned np = negate(p); - max = std::max(max, std::max(np, p) + 1); - } - m_next.reserve(max); - m_tc.reserve(m_next.size()); + init(ps); unsigned_vector clique; uint_set vars; - for (unsigned i = 0; i < num_ps; ++i) { - vars.insert(ps[i]); - } + for (unsigned v : ps) + vars.insert(v); while (!vars.empty()) { clique.reset(); @@ -118,9 +108,8 @@ public: m_reachable[turn].remove(p); vars.remove(p); clique.push_back(p); - if (m_reachable[turn].empty()) { + if (m_reachable[turn].empty()) break; - } m_reachable[!turn].reset(); get_reachable(p, m_reachable[turn], m_reachable[!turn]); turn = !turn; @@ -129,10 +118,75 @@ public: if (clique.size() == 2 && clique[0] == negate(clique[1])) { // no op } - else { + else cliques.push_back(clique); + } + } + } + + + // better quality cliques + void cliques2(unsigned_vector const& ps, vector& cliques) { + + uint_set all_vars, todo; + u_map conns; + + init(ps); + + struct compare_degree { + u_map& conns; + compare_degree(u_map& conns): conns(conns) {} + bool operator()(unsigned x, unsigned y) const { + return conns[x].num_elems() < conns[y].num_elems(); + } + }; + compare_degree lt(conns); + heap heap(m_next.size(), lt); + + for (unsigned p : ps) { + all_vars.insert(p); + todo.insert(p); + } + + for (unsigned v : ps) { + uint_set reach; + get_reachable(v, all_vars, reach); + conns.insert(v, reach); + heap.insert(v); + } + + while (!todo.empty()) { + unsigned v = heap.min_value(); + uint_set am1; + unsigned_vector next; + for (unsigned n : conns[v]) + if (todo.contains(n)) + next.push_back(n); + std::sort(next.begin(), next.end(), [&](unsigned a, unsigned b) { return conns[a].num_elems() < conns[b].num_elems(); }); + for (unsigned x : next) { + if (std::all_of(am1.begin(), am1.end(), [&](unsigned y) { return conns[x].contains(y); })) + am1.insert(x); + } + am1.insert(v); + for (unsigned x : am1) { + todo.remove(x); + for (unsigned y : conns[x]) { + conns[y].remove(x); + heap.decreased(y); } } + for (unsigned x : am1) + heap.erase(x); + + if (am1.num_elems() > 1) { + unsigned_vector mux; + for (unsigned x : am1) + mux.push_back(x); + if (mux.size() == 2 && mux[0] == negate(mux[1])) { + continue; + } + cliques.push_back(mux); + } } } From cc36dd1e0d4d998d62b6f8e8c1807c56699e0729 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 19:18:17 +0200 Subject: [PATCH 249/258] include map for non vs builds Signed-off-by: Nikolaj Bjorner --- src/util/max_cliques.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index ad6bc0219..1e1611b45 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -21,7 +21,7 @@ Notes: #include "util/vector.h" #include "util/uint_set.h" #include "util/heap.h" - +#include "util/map.h" template class max_cliques : public T { From c33611e9e07fb3a49acfd63ab9659169d41078c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 19:23:48 +0200 Subject: [PATCH 250/258] include map for non vs builds Signed-off-by: Nikolaj Bjorner --- src/util/max_cliques.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 1e1611b45..4dd91b366 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -164,7 +164,14 @@ public: next.push_back(n); std::sort(next.begin(), next.end(), [&](unsigned a, unsigned b) { return conns[a].num_elems() < conns[b].num_elems(); }); for (unsigned x : next) { - if (std::all_of(am1.begin(), am1.end(), [&](unsigned y) { return conns[x].contains(y); })) + bool all = true; + for (unsigned y : am1) { + if (!conns[x].contains(y)) { + all = false; + break; + } + } + if (all) am1.insert(x); } am1.insert(v); From 9ecd4f840683e6928cc693b7235de7128321c1f1 Mon Sep 17 00:00:00 2001 From: Zachary Wimer Date: Fri, 15 Apr 2022 10:53:16 -0700 Subject: [PATCH 251/258] MANIFEST.in will now include pyproject.toml (#5979) --- src/api/python/MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/python/MANIFEST.in b/src/api/python/MANIFEST.in index 35a0627e5..7317d7b21 100644 --- a/src/api/python/MANIFEST.in +++ b/src/api/python/MANIFEST.in @@ -5,3 +5,4 @@ recursive-include core *.cmake recursive-include core/src * recursive-include core/cmake * recursive-include core/scripts * +include pyproject.toml From e11496bc65beb4b15aa7805413254d3c73407cc7 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Fri, 15 Apr 2022 20:07:17 +0200 Subject: [PATCH 252/258] Added decide-callback to user-propagator (#5978) * Fixed registering expressions in push/pop * Reused existing function * Reverted reusing can_propagate * Added decide-callback to user-propagator * Refactoring * Fixed index --- src/api/api_solver.cpp | 8 ++ src/api/c++/z3++.h | 31 +++++- src/api/z3_api.h | 9 ++ src/smt/smt_context.cpp | 157 +++++++++++++++-------------- src/smt/smt_context.h | 10 ++ src/smt/smt_kernel.cpp | 4 + src/smt/smt_kernel.h | 2 + src/smt/smt_solver.cpp | 4 + src/smt/tactic/smt_tactic_core.cpp | 2 + src/smt/theory_bv.cpp | 34 ++++++- src/smt/theory_bv.h | 6 ++ src/smt/theory_user_propagator.cpp | 69 +++++++++++++ src/smt/theory_user_propagator.h | 6 +- src/solver/tactic2solver.cpp | 4 + src/tactic/tactical.cpp | 4 + src/tactic/user_propagator_base.h | 21 ++-- 16 files changed, 284 insertions(+), 87 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index c9eda8712..a0803516f 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -975,6 +975,14 @@ extern "C" { Z3_CATCH; } + void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh) { + Z3_TRY; + RESET_ERROR_CODE(); + user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr*&, unsigned&, lbool&))decide_eh; + to_solver_ref(s)->user_propagate_register_decide(c); + Z3_CATCH; + } + Z3_func_decl Z3_API Z3_solver_propagate_declare(Z3_context c, Z3_symbol name, unsigned n, Z3_sort* domain, Z3_sort range) { Z3_TRY; LOG_Z3_solver_propagate_declare(c, name, n, domain, range); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 101fa04a3..57a87415d 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -3943,11 +3943,13 @@ namespace z3 { typedef std::function final_eh_t; typedef std::function eq_eh_t; typedef std::function created_eh_t; + typedef std::function decide_eh_t; final_eh_t m_final_eh; eq_eh_t m_eq_eh; fixed_eh_t m_fixed_eh; created_eh_t m_created_eh; + decide_eh_t m_decide_eh; solver* s; context* c; std::vector subcontexts; @@ -4009,8 +4011,15 @@ namespace z3 { expr e(p->ctx(), _e); p->m_created_eh(e); } - - + + static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast& _val, unsigned& bit, Z3_lbool& is_pos) { + user_propagator_base* p = static_cast(_p); + scoped_cb _cb(p, cb); + expr val(p->ctx(), _val); + p->m_decide_eh(val, bit, is_pos); + _val = val; + } + public: user_propagator_base(context& c) : s(nullptr), c(&c) {} @@ -4119,6 +4128,22 @@ namespace z3 { Z3_solver_propagate_created(ctx(), *s, created_eh); } } + + void register_decide(decide_eh_t& c) { + m_decide_eh = c; + if (s) { + Z3_solver_propagate_decide(ctx(), *s, decide_eh); + } + } + + void register_decide() { + m_decide_eh = [this](expr& val, unsigned& bit, Z3_lbool& is_pos) { + decide(val, bit, is_pos); + }; + if (s) { + Z3_solver_propagate_decide(ctx(), *s, decide_eh); + } + } virtual void fixed(expr const& /*id*/, expr const& /*e*/) { } @@ -4127,6 +4152,8 @@ namespace z3 { virtual void final() { } virtual void created(expr const& /*e*/) {} + + virtual void decide(expr& /*val*/, unsigned& /*bit*/, Z3_lbool& /*is_pos*/) {} /** \brief tracks \c e by a unique identifier that is returned by the call. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 1388d0ab1..1eb2164d5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1444,6 +1444,7 @@ Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb)); Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t)); +Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast&, unsigned&, Z3_lbool&)); /** @@ -6758,6 +6759,14 @@ extern "C" { * The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare. */ void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh); + + /** + * \brief register a callback when a the solver decides to split on a registered expression + * The callback may set passed expression to another registered expression which will be selected instead. + * In case the expression is a bitvector the bit to split on is determined by the bit argument and the + * truth-value to try first is given by is_pos + */ + void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh); /** Create uninterpreted function declaration for the user propagator. diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a9b44ab3c..3e444bec7 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1766,6 +1766,70 @@ namespace smt { m_bvar_inc *= INV_ACTIVITY_LIMIT; } + /** + \brief Returns a truth value for the given variable + */ + bool context::guess(bool_var var, lbool phase) { + if (is_quantifier(m_bool_var2expr[var])) { + // Overriding any decision on how to assign the quantifier. + // assigning a quantifier to false is equivalent to make it irrelevant. + phase = l_false; + } + literal l(var, false); + + if (phase != l_undef) + return phase == l_true; + + bool_var_data & d = m_bdata[var]; + if (d.try_true_first()) + return true; + switch (m_fparams.m_phase_selection) { + case PS_THEORY: + if (m_phase_cache_on && d.m_phase_available) { + return m_bdata[var].m_phase; + } + if (!m_phase_cache_on && d.is_theory_atom()) { + theory * th = m_theories.get_plugin(d.get_theory()); + lbool th_phase = th->get_phase(var); + if (th_phase != l_undef) { + return th_phase == l_true; + } + } + if (track_occs()) { + if (m_lit_occs[l.index()] == 0) { + return false; + } + if (m_lit_occs[(~l).index()] == 0) { + return true; + } + } + return m_phase_default; + case PS_CACHING: + case PS_CACHING_CONSERVATIVE: + case PS_CACHING_CONSERVATIVE2: + if (m_phase_cache_on && d.m_phase_available) { + TRACE("phase_selection", tout << "using cached value, is_pos: " << m_bdata[var].m_phase << ", var: p" << var << "\n";); + return m_bdata[var].m_phase; + } + else { + TRACE("phase_selection", tout << "setting to false\n";); + return m_phase_default; + } + case PS_ALWAYS_FALSE: + return false; + case PS_ALWAYS_TRUE: + return true; + case PS_RANDOM: + return m_random() % 2 == 0; + case PS_OCCURRENCE: { + return m_lit_occs[l.index()] > m_lit_occs[(~l).index()]; + } + default: + UNREACHABLE(); + return false; + } + } + /** \brief Execute next case split, return false if there are no more case splits to be performed. @@ -1807,81 +1871,15 @@ namespace smt { TRACE("decide", tout << "splitting, lvl: " << m_scope_lvl << "\n";); TRACE("decide_detail", tout << mk_pp(bool_var2expr(var), m) << "\n";); - - bool is_pos; - - if (is_quantifier(m_bool_var2expr[var])) { - // Overriding any decision on how to assign the quantifier. - // assigning a quantifier to false is equivalent to make it irrelevant. - phase = l_false; - } + + bool is_pos = guess(var, phase); literal l(var, false); - if (phase != l_undef) { - is_pos = phase == l_true; - } - else { - bool_var_data & d = m_bdata[var]; - if (d.try_true_first()) { - is_pos = true; - } - else { - switch (m_fparams.m_phase_selection) { - case PS_THEORY: - if (m_phase_cache_on && d.m_phase_available) { - is_pos = m_bdata[var].m_phase; - break; - } - if (!m_phase_cache_on && d.is_theory_atom()) { - theory * th = m_theories.get_plugin(d.get_theory()); - lbool th_phase = th->get_phase(var); - if (th_phase != l_undef) { - is_pos = th_phase == l_true; - break; - } - } - if (track_occs()) { - if (m_lit_occs[l.index()] == 0) { - is_pos = false; - break; - } - if (m_lit_occs[(~l).index()] == 0) { - is_pos = true; - break; - } - } - is_pos = m_phase_default; - break; - case PS_CACHING: - case PS_CACHING_CONSERVATIVE: - case PS_CACHING_CONSERVATIVE2: - if (m_phase_cache_on && d.m_phase_available) { - TRACE("phase_selection", tout << "using cached value, is_pos: " << m_bdata[var].m_phase << ", var: p" << var << "\n";); - is_pos = m_bdata[var].m_phase; - } - else { - TRACE("phase_selection", tout << "setting to false\n";); - is_pos = m_phase_default; - } - break; - case PS_ALWAYS_FALSE: - is_pos = false; - break; - case PS_ALWAYS_TRUE: - is_pos = true; - break; - case PS_RANDOM: - is_pos = (m_random() % 2 == 0); - break; - case PS_OCCURRENCE: { - is_pos = m_lit_occs[l.index()] > m_lit_occs[(~l).index()]; - break; - } - default: - is_pos = false; - UNREACHABLE(); - } - } + bool_var original_choice = var; + + if (decide_user_interference(var, is_pos)) { + m_case_split_queue->unassign_var_eh(original_choice); + l = literal(var, false); } if (!is_pos) l.neg(); @@ -1889,7 +1887,7 @@ namespace smt { assign(l, b_justification::mk_axiom(), true); return true; } - + /** \brief Update counter that is used to enable/disable phase caching. */ @@ -2906,6 +2904,14 @@ namespace smt { return m_user_propagator && m_user_propagator->has_fixed() && n->get_th_var(m_user_propagator->get_family_id()) != null_theory_var; } + bool context::decide_user_interference(bool_var& var, bool& is_pos) { + if (!m_user_propagator || !m_user_propagator->has_decide()) + return false; + bool_var old = var; + m_user_propagator->decide(var, is_pos); + return old != var; + } + void context::assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain) { theory_var v = n->get_th_var(m_user_propagator->get_family_id()); m_user_propagator->new_fixed_eh(v, val, sz, explain); @@ -3042,7 +3048,8 @@ namespace smt { } } } - } else { + } + else { literal_vector new_case_split; for (unsigned i = 0; i < num_lits; ++i) { literal l = lits[i]; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 637c2171b..696a5cc39 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1134,6 +1134,8 @@ namespace smt { enode * get_enode_eq_to(func_decl * f, unsigned num_args, enode * const * args); + bool guess(bool_var var, lbool phase); + protected: bool decide(); @@ -1738,8 +1740,16 @@ namespace smt { m_user_propagator->register_created(r); } + void user_propagate_register_decide(user_propagator::decide_eh_t& r) { + if (!m_user_propagator) + throw default_exception("user propagator must be initialized"); + m_user_propagator->register_decide(r); + } + bool watches_fixed(enode* n) const; + bool decide_user_interference(bool_var& var, bool& is_pos); + void assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain); void assign_fixed(enode* n, expr* val, literal_vector const& explain) { diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 2d082170c..8f442596c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -284,4 +284,8 @@ namespace smt { m_imp->m_kernel.user_propagate_register_created(r); } + void kernel::user_propagate_register_decide(user_propagator::decide_eh_t& r) { + m_imp->m_kernel.user_propagate_register_decide(r); + } + }; diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 068bd1b52..4fa840f5e 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -311,6 +311,8 @@ namespace smt { void user_propagate_register_created(user_propagator::created_eh_t& r); + void user_propagate_register_decide(user_propagator::decide_eh_t& r); + /** \brief Return a reference to smt::context. This breaks abstractions. diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 344cf9e6f..5064ed7ef 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -244,6 +244,10 @@ namespace { m_context.user_propagate_register_created(c); } + void user_propagate_register_decide(user_propagator::decide_eh_t& c) override { + m_context.user_propagate_register_decide(c); + } + struct scoped_minimize_core { smt_solver& s; expr_ref_vector m_assumptions; diff --git a/src/smt/tactic/smt_tactic_core.cpp b/src/smt/tactic/smt_tactic_core.cpp index 072e1ed24..9c5fc1c8e 100644 --- a/src/smt/tactic/smt_tactic_core.cpp +++ b/src/smt/tactic/smt_tactic_core.cpp @@ -322,6 +322,7 @@ public: user_propagator::eq_eh_t m_eq_eh; user_propagator::eq_eh_t m_diseq_eh; user_propagator::created_eh_t m_created_eh; + user_propagator::decide_eh_t m_decide_eh; void user_propagate_delay_init() { @@ -333,6 +334,7 @@ public: if (m_eq_eh) m_ctx->user_propagate_register_eq(m_eq_eh); if (m_diseq_eh) m_ctx->user_propagate_register_diseq(m_diseq_eh); if (m_created_eh) m_ctx->user_propagate_register_created(m_created_eh); + if (m_decide_eh) m_ctx->user_propagate_register_decide(m_decide_eh); for (expr* v : m_vars) m_ctx->user_propagate_register_expr(v); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 341daedec..682f4d6f9 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -531,7 +531,6 @@ namespace smt { return true; } - bool theory_bv::get_fixed_value(theory_var v, numeral & result) const { result.reset(); unsigned i = 0; @@ -1821,6 +1820,39 @@ namespace smt { st.update("bv dynamic eqs", m_stats.m_num_eq_dynamic); } + theory_bv::var_enode_pos theory_bv::get_bv_with_theory(bool_var v, theory_id id) const { + atom* a = get_bv2a(v); + svector vec; + if (!a->is_bit()) + return var_enode_pos(nullptr, UINT32_MAX); + bit_atom * b = static_cast(a); + var_pos_occ * curr = b->m_occs; + while (curr) { + enode* n = get_enode(curr->m_var); + if (n->get_th_var(id) != null_theory_var) + return var_enode_pos(n, curr->m_idx); + curr = curr->m_next; + } + return var_enode_pos(nullptr, UINT32_MAX); + } + + bool_var theory_bv::get_first_unassigned(unsigned start_bit, enode* n) const { + theory_var v = n->get_th_var(get_family_id()); + auto& bits = m_bits[v]; + unsigned sz = bits.size(); + + for (unsigned i = start_bit; i < sz; ++i) { + if (ctx.get_assignment(bits[i].var()) != l_undef) + return bits[i].var(); + } + for (unsigned i = 0; i < start_bit; ++i) { + if (ctx.get_assignment(bits[i].var()) != l_undef) + return bits[i].var(); + } + + return null_bool_var; + } + bool theory_bv::check_assignment(theory_var v) { if (!is_root(v)) return true; diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index ebca3fa83..d73b7a008 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -260,6 +260,9 @@ namespace smt { smt_params const& params() const; public: + + typedef std::pair var_enode_pos; + theory_bv(context& ctx); ~theory_bv() override; @@ -284,6 +287,9 @@ namespace smt { bool get_fixed_value(app* x, numeral & result) const; bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector& explain) override; + var_enode_pos get_bv_with_theory(bool_var v, theory_id id) const; + bool_var get_first_unassigned(unsigned start_bit, enode* n) const; + bool check_assignment(theory_var v); bool check_invariant(); bool check_zero_one_bits(theory_var v); diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index f783f22fb..bf8722701 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -17,6 +17,7 @@ Author: #include "ast/ast_pp.h" +#include "smt/theory_bv.h" #include "smt/theory_user_propagator.h" #include "smt/smt_context.h" @@ -116,6 +117,7 @@ theory * theory_user_propagator::mk_fresh(context * new_ctx) { if ((bool)m_eq_eh) th->register_eq(m_eq_eh); if ((bool)m_diseq_eh) th->register_diseq(m_diseq_eh); if ((bool)m_created_eh) th->register_created(m_created_eh); + if ((bool)m_decide_eh) th->register_decide(m_decide_eh); return th; } @@ -154,6 +156,73 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu } } +void theory_user_propagator::decide(bool_var& var, bool& is_pos) { + + const bool_var_data& d = ctx.get_bdata(var); + + if (!d.is_theory_atom()) + return; + + theory* th = ctx.get_theory(d.get_theory()); + + bv_util bv(m); + enode* original_enode = nullptr; + unsigned original_bit = 0; + + if (d.is_enode() && th->get_family_id() == get_family_id()) { + // variable is just a registered expression + original_enode = ctx.bool_var2enode(var); + } + else if (th->get_family_id() == bv.get_fid()) { + // it might be a registered bit-vector + auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id()); + if (!registered_bv.first) + // there is no registered bv associated with the bit + return; + original_enode = registered_bv.first; + original_bit = registered_bv.second; + } + else + return; + + // call the registered callback + unsigned new_bit = original_bit; + lbool phase = is_pos ? l_true : l_false; + + expr* e = var2expr(original_enode->get_th_var(get_family_id())); + m_decide_eh(m_user_context, this, e, new_bit, phase); + enode* new_enode = ctx.get_enode(e); + + // check if the callback changed something + if (original_enode == new_enode && (new_enode->is_bool() || original_bit == new_bit)) { + if (phase != l_undef) + // it only affected the truth value + is_pos = phase == l_true; + return; + } + + bool_var old_var = var; + if (new_enode->is_bool()) { + // expression was set to a boolean + bool_var new_var = ctx.enode2bool_var(new_enode); + if (ctx.get_assignment(new_var) == l_undef) { + var = new_var; + } + } + else { + // expression was set to a bit-vector + auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid()); + bool_var new_var = th_bv->get_first_unassigned(new_bit, new_enode); + + if (new_var != null_bool_var) { + var = new_var; + } + } + + // in case the callback did not decide on a truth value -> let Z3 decide + is_pos = ctx.guess(var, phase); +} + void theory_user_propagator::push_scope_eh() { ++m_num_scopes; } diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index 9b271e9c3..bf82883e4 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -56,7 +56,7 @@ namespace smt { void reset() { memset(this, 0, sizeof(*this)); } }; - void* m_user_context = nullptr; + void* m_user_context = nullptr; user_propagator::push_eh_t m_push_eh; user_propagator::pop_eh_t m_pop_eh; user_propagator::fresh_eh_t m_fresh_eh; @@ -65,6 +65,7 @@ namespace smt { user_propagator::eq_eh_t m_eq_eh; user_propagator::eq_eh_t m_diseq_eh; user_propagator::created_eh_t m_created_eh; + user_propagator::decide_eh_t m_decide_eh; user_propagator::context_obj* m_api_context = nullptr; unsigned m_qhead = 0; @@ -121,13 +122,16 @@ namespace smt { void register_eq(user_propagator::eq_eh_t& eq_eh) { m_eq_eh = eq_eh; } void register_diseq(user_propagator::eq_eh_t& diseq_eh) { m_diseq_eh = diseq_eh; } void register_created(user_propagator::created_eh_t& created_eh) { m_created_eh = created_eh; } + void register_decide(user_propagator::decide_eh_t& decide_eh) { m_decide_eh = decide_eh; } bool has_fixed() const { return (bool)m_fixed_eh; } + bool has_decide() const { return (bool)m_decide_eh; } void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override; void register_cb(expr* e) override; void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits); + void decide(bool_var& var, bool& is_pos); theory * mk_fresh(context * new_ctx) override; bool internalize_atom(app* atom, bool gate_ctx) override; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index e8a30a009..fe89d6533 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -116,6 +116,10 @@ public: m_tactic->user_propagate_register_created(created_eh); } + void user_propagate_register_decide(user_propagator::decide_eh_t& created_eh) override { + m_tactic->user_propagate_register_decide(created_eh); + } + void user_propagate_clear() override { if (m_tactic) m_tactic->user_propagate_clear(); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 9167650ad..67a0e3062 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -204,6 +204,10 @@ public: m_t2->user_propagate_register_created(created_eh); } + void user_propagate_register_decide(user_propagator::decide_eh_t& decide_eh) override { + m_t2->user_propagate_register_decide(decide_eh); + } + }; tactic * and_then(tactic * t1, tactic * t2) { diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 02a027762..c67a073cd 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -2,6 +2,7 @@ #pragma once #include "ast/ast.h" +#include "util/lbool.h" namespace user_propagator { @@ -17,14 +18,14 @@ namespace user_propagator { virtual ~context_obj() = default; }; - typedef std::function final_eh_t; - typedef std::function fixed_eh_t; - typedef std::function eq_eh_t; - typedef std::function fresh_eh_t; - typedef std::function push_eh_t; - typedef std::function pop_eh_t; - typedef std::function created_eh_t; - + typedef std::function final_eh_t; + typedef std::function fixed_eh_t; + typedef std::function eq_eh_t; + typedef std::function fresh_eh_t; + typedef std::function push_eh_t; + typedef std::function pop_eh_t; + typedef std::function created_eh_t; + typedef std::function decide_eh_t; class plugin : public decl_plugin { public: @@ -85,6 +86,10 @@ namespace user_propagator { throw default_exception("user-propagators are only supported on the SMT solver"); } + virtual void user_propagate_register_decide(decide_eh_t& r) { + throw default_exception("user-propagators are only supported on the SMT solver"); + } + virtual void user_propagate_clear() { } From 11d992a3352e2b1d172af5c3b3e066ce28cd65cc Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 15 Apr 2022 14:08:39 -0400 Subject: [PATCH 253/258] wip: tweak GC further (#5982) --- src/api/ml/z3native_stubs.c.pre | 42 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index 895e20235..0efaa110f 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -294,7 +294,8 @@ static struct custom_operations Z3_ast_plus_custom_ops = { Z3_ast_compare_ext }; -MK_CTX_OF(ast, 16) // let's say 16 bytes per ast +// FUDGE +MK_CTX_OF(ast, 8) // let's say 16 bytes per ast #define MK_PLUS_OBJ_NO_REF(X, USED) \ typedef struct { \ @@ -410,25 +411,26 @@ MK_CTX_OF(ast, 16) // let's say 16 bytes per ast \ MK_CTX_OF(X, USED) -MK_PLUS_OBJ_NO_REF(symbol, 32) -MK_PLUS_OBJ_NO_REF(constructor, 32) -MK_PLUS_OBJ_NO_REF(constructor_list, 32) -MK_PLUS_OBJ_NO_REF(rcf_num, 32) -MK_PLUS_OBJ(params, 128) -MK_PLUS_OBJ(param_descrs, 128) -MK_PLUS_OBJ(model, 512) -MK_PLUS_OBJ(func_interp, 128) -MK_PLUS_OBJ(func_entry, 128) -MK_PLUS_OBJ(goal, 128) -MK_PLUS_OBJ(tactic, 128) -MK_PLUS_OBJ(probe, 128) -MK_PLUS_OBJ(apply_result, 128) -MK_PLUS_OBJ(solver, 20 * 1000 * 1000) // pretend a solver is 20MB -MK_PLUS_OBJ(stats, 128) -MK_PLUS_OBJ(ast_map, 1024 * 2) -MK_PLUS_OBJ(ast_vector, 128) -MK_PLUS_OBJ(fixedpoint, 20 * 1000 * 1000) -MK_PLUS_OBJ(optimize, 20 * 1000 * 1000) +// FUDGE +MK_PLUS_OBJ_NO_REF(symbol, 16) +MK_PLUS_OBJ_NO_REF(constructor, 16) +MK_PLUS_OBJ_NO_REF(constructor_list, 16) +MK_PLUS_OBJ_NO_REF(rcf_num, 16) +MK_PLUS_OBJ(params, 64) +MK_PLUS_OBJ(param_descrs, 64) +MK_PLUS_OBJ(model, 64) +MK_PLUS_OBJ(func_interp, 32) +MK_PLUS_OBJ(func_entry, 32) +MK_PLUS_OBJ(goal, 64) +MK_PLUS_OBJ(tactic, 64) +MK_PLUS_OBJ(probe, 64) +MK_PLUS_OBJ(apply_result, 32) +MK_PLUS_OBJ(solver, 20 * 1000) +MK_PLUS_OBJ(stats, 32) +MK_PLUS_OBJ(ast_map, 32) +MK_PLUS_OBJ(ast_vector, 32) +MK_PLUS_OBJ(fixedpoint, 20 * 1000) +MK_PLUS_OBJ(optimize, 20 * 1000) #ifdef __cplusplus extern "C" { From 8e701128322ed9ea6e9f42573e9346c811099fab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Apr 2022 23:31:15 +0200 Subject: [PATCH 254/258] Update z3.py allow ading funcinterp to models --- src/api/python/z3/z3.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 223b3e038..ed9c7f0a8 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6594,6 +6594,19 @@ class ModelRef(Z3PPObject): """Update the interpretation of a constant""" if is_expr(x): x = x.decl() + if is_func_decl(x) and x.arity() != 0 and isinstance(value, FuncInterp): + fi1 = value.f + fi2 = Z3_add_func_interp(x.ctx_ref(), self.model, x.ast, value.else_value().ast); + fi2 = FuncInterp(fi2, x.ctx) + for i in range(value.num_entries()): + e = value.entry(i) + n = Z3_func_entry_get_num_args(x.ctx_ref(), e.entry) + v = AstVector() + for j in range(n): + v.push(entry.arg_value(j)) + val = Z3_func_entry_get_value(x.ctx_ref(), e.entry) + Z3_func_interp_add_entry(x.ctx_ref(), fi2.f, v.vector, val) + return if not is_func_decl(x) or x.arity() != 0: raise Z3Exception("Expecting 0-ary function or constant expression") value = _py2expr(value) From 807121aa03161fbd777a4ae57e865a958bb89684 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 14:55:43 +0200 Subject: [PATCH 255/258] wip --- src/opt/maxres.cpp | 83 ++++++++++++++++++++++++++++++++++ src/opt/opt_preprocess.cpp | 86 ++++++++++++++++++++++++++++++++++++ src/opt/opt_preprocess.h | 2 + src/smt/smt_consequences.cpp | 2 +- src/util/max_cliques.h | 63 ++++++++++++++++---------- 5 files changed, 212 insertions(+), 24 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 135e0f80e..d316f9360 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -649,6 +649,7 @@ public: } } + void max_resolve(exprs const& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); @@ -699,6 +700,88 @@ public: } } +#if 0 + + void bin_max_resolve(exprs const& _core, rational const& w) { + expr_ref_vector core(m, _core.size(), _core.data()); + expr_ref fml(m), cls(m); + for (unsigned i = 0; i + 1 < core.size(); ++i) { + expr* a = core.get(i); + expr* b = core.get(i + 1); + expr_ref u = mk_fresh_bool("u"); + expr_ref v = mk_fresh_bool("v"); + // u = a or b + // v = a and b + cls = m.mk_or(a, b); + fml = m.mk_implies(u, cls); + add(fml); + update_model(u, cls); + m_defs.push_back(fml); + cls = m.mk_and(a, b); + fml = m.mk_implies(v, cls); + add(fml); + update_model(v, cls); + m_defs.push_back(fml); + new_assumption(u, w); + core.push_back(v); + } + } + + struct unfold_record { + ptr_vector ws; + rational weight; + }; + + void bin_delay_max_resolve(exprs const& _core, rational const& w) { + expr_ref_vector core(m, _core.size(), _core.data()), us(m), partial(m); + expr_ref fml(m), cls(m); + for (expr* c : core) { + unfold_record ws; + if (!m_unfold.find(c, ws)) + continue; + for (expr* f : ws.ws) + new_assumption(f, ws.weight); + } + if (core.size() <= 1) + return; + + for (expr* core) + partial.push_back(nullptr); + + for (unsigned i = 0; i + 1 < core.size(); ++i) { + expr* a = core.get(i); + expr* b = core.get(i + 1); + expr_ref u = mk_fresh_bool("u"); + expr_ref v = mk_fresh_bool("v"); + // u = a or b + // v = a and b + cls = m.mk_or(a, b); + fml = m.mk_implies(u, cls); + add(fml); + update_model(u, cls); + m_defs.push_back(fml); + cls = m.mk_and(a, b); + fml = m.mk_implies(v, cls); + add(fml); + update_model(v, cls); + m_defs.push_back(fml); + us.push_back(u); + core.push_back(v); + + unfold_record r; + r.ws.push_back(u); + if (partial.get(i)) + r.ws.push_back(partia.get(i)); + if (partial.get(i + 1)) + r.ws.push_back(partia.get(i + 1)); + partial.push_back(m.mk_and(r.ws)); + m_unfold.insert(partial.back(), r); + } + expr_ref u = mk_and(us); + new_assumption(u, w); + } +#endif + // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { if (cs.empty()) return; diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index 6cbc8b1b9..bbf119266 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -20,9 +20,93 @@ Author: #pragma once #include "opt/opt_preprocess.h" +#include "util/max_cliques.h" namespace opt { + expr_ref_vector preprocess::propagate(expr* f, lbool& is_sat) { + expr_ref_vector asms(m); + asms.push_back(f); + is_sat = s.check_sat(asms); + return s.get_trail(1); + } + + bool preprocess::prop_mutexes(vector& softs, rational& lower) { + expr_ref_vector fmls(m); + obj_map new_soft = soft2map(softs, fmls); + + params_ref p; + p.set_uint("max_conflicts", 1); + s.updt_params(p); + + obj_hashtable pfmls, nfmls; + for (expr* f : fmls) + if (m.is_not(f, f)) + nfmls.insert(f); + else + pfmls.insert(f); + + u_map ids; + unsigned_vector ps; + for (expr* f : fmls) { + ids.insert(f->get_id(), f); + ps.push_back(f->get_id()); + } + + u_map conns; + + for (expr* f : fmls) { + lbool is_sat; + expr_ref_vector trail = propagate(f, is_sat); + if (is_sat == l_false) { + rational w = new_soft[f]; + lower += w; + s.assert_expr(m.mk_not(f)); + new_soft.remove(f); + continue; + } + + expr_ref_vector mux(m); + for (expr* g : trail) { + if (m.is_not(g, g)) { + if (pfmls.contains(g)) + mux.push_back(g); + } + else if (nfmls.contains(g)) + mux.push_back(m.mk_not(g)); + } + uint_set reach; + for (expr* g : mux) + reach.insert(g->get_id()); + conns.insert(f->get_id(), reach); + } + + p.set_uint("max_conflicts", UINT_MAX); + s.updt_params(p); + + struct neg_literal { + unsigned negate(unsigned id) { + throw default_exception("unexpected call"); + } + }; + max_cliques mc; + vector mutexes; + mc.cliques(ps, conns, mutexes); + + for (auto& mux : mutexes) { + expr_ref_vector _mux(m); + for (auto p : mux) + _mux.push_back(ids[p]); + process_mutex(_mux, new_soft, lower); + } + + softs.reset(); + for (auto const& [k, v] : new_soft) + softs.push_back(soft(expr_ref(k, m), v, false)); + m_trail.reset(); + return true; + } + obj_map preprocess::soft2map(vector const& softs, expr_ref_vector& fmls) { obj_map new_soft; for (soft const& sf : softs) { @@ -104,6 +188,8 @@ namespace opt { bool preprocess::operator()(vector& soft, rational& lower) { if (!find_mutexes(soft, lower)) return false; + if (false && !prop_mutexes(soft, lower)) + return false; return true; } }; diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h index f5f1c9db6..567a750ed 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -28,8 +28,10 @@ namespace opt { solver& s; expr_ref_vector m_trail; + expr_ref_vector propagate(expr* f, lbool& is_sat); obj_map soft2map(vector const& softs, expr_ref_vector& fmls); bool find_mutexes(vector& softs, rational& lower); + bool prop_mutexes(vector& softs, rational& lower); void process_mutex(expr_ref_vector& mutex, obj_map& new_soft, rational& lower); public: diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index b54e92a70..657e222da 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -612,7 +612,7 @@ namespace smt { } } vector _mutexes; - mc.cliques(ps, _mutexes); + mc.cliques2(ps, _mutexes); for (auto const& mux : _mutexes) { expr_ref_vector lits(m); for (unsigned idx : mux) { diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 4dd91b366..979a5b795 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -83,6 +83,29 @@ class max_cliques : public T { m_next.reserve(max); m_tc.reserve(m_next.size()); } + + struct compare_degree { + u_map& conns; + compare_degree(u_map& conns): conns(conns) {} + bool operator()(unsigned x, unsigned y) const { + return conns[x].num_elems() < conns[y].num_elems(); + } + }; + + + void init(unsigned_vector const& ps, u_map& conns) { + + uint_set vars; + + for (unsigned p : ps) + vars.insert(p); + + for (unsigned v : ps) { + uint_set reach; + get_reachable(v, vars, reach); + conns.insert(v, reach); + } + } public: void add_edge(unsigned src, unsigned dst) { @@ -92,7 +115,7 @@ public: m_next[dst].push_back(src); } - void cliques(unsigned_vector const& ps, vector& cliques) { + void cliques1(unsigned_vector const& ps, vector& cliques) { init(ps); unsigned_vector clique; uint_set vars; @@ -124,35 +147,29 @@ public: } } - // better quality cliques - void cliques2(unsigned_vector const& ps, vector& cliques) { - - uint_set all_vars, todo; + void cliques2(unsigned_vector const& ps, vector& cs) { u_map conns; - init(ps); + // compute connections using TC of implication graph + init(ps, conns); + cliques(ps, conns, cs); + } - struct compare_degree { - u_map& conns; - compare_degree(u_map& conns): conns(conns) {} - bool operator()(unsigned x, unsigned y) const { - return conns[x].num_elems() < conns[y].num_elems(); - } - }; + // cliques after connections are computed. + void cliques(unsigned_vector const& ps, u_map& conns, vector& cliques) { + + unsigned maxp = 1; + for (unsigned p : ps) + maxp = std::max(p, maxp); + + uint_set todo; compare_degree lt(conns); - heap heap(m_next.size(), lt); + heap heap(maxp + 1, lt); - for (unsigned p : ps) { - all_vars.insert(p); + for (unsigned p : ps) { todo.insert(p); - } - - for (unsigned v : ps) { - uint_set reach; - get_reachable(v, all_vars, reach); - conns.insert(v, reach); - heap.insert(v); + heap.insert(p); } while (!todo.empty()) { From f4c500c5197f559870e1fd78bd52496024493c4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 15:16:53 +0200 Subject: [PATCH 256/258] fix build reference types are not part of C --- src/api/api_solver.cpp | 2 +- src/api/z3_api.h | 2 +- src/opt/maxres.cpp | 11 ++++++++--- src/smt/theory_user_propagator.cpp | 2 +- src/tactic/user_propagator_base.h | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index a0803516f..05b125546 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -978,7 +978,7 @@ extern "C" { void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh) { Z3_TRY; RESET_ERROR_CODE(); - user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr*&, unsigned&, lbool&))decide_eh; + user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr**, unsigned*, lbool*))decide_eh; to_solver_ref(s)->user_propagate_register_decide(c); Z3_CATCH; } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 1eb2164d5..2680b6f82 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1444,7 +1444,7 @@ Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t)); Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb)); Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t)); -Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast&, unsigned&, Z3_lbool&)); +Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast*, unsigned*, Z3_lbool*)); /** diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d316f9360..4c9964cf4 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -700,7 +700,7 @@ public: } } -#if 0 +#if 1 void bin_max_resolve(exprs const& _core, rational const& w) { expr_ref_vector core(m, _core.size(), _core.data()); @@ -708,8 +708,8 @@ public: for (unsigned i = 0; i + 1 < core.size(); ++i) { expr* a = core.get(i); expr* b = core.get(i + 1); - expr_ref u = mk_fresh_bool("u"); - expr_ref v = mk_fresh_bool("v"); + expr* u = mk_fresh_bool("u"); + expr* v = mk_fresh_bool("v"); // u = a or b // v = a and b cls = m.mk_or(a, b); @@ -725,8 +725,13 @@ public: new_assumption(u, w); core.push_back(v); } + s().assert_expr(m.mk_not(core.back())); } +#endif + +#if 0 + struct unfold_record { ptr_vector ws; rational weight; diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index bf8722701..1b0cc429d 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -190,7 +190,7 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) { lbool phase = is_pos ? l_true : l_false; expr* e = var2expr(original_enode->get_th_var(get_family_id())); - m_decide_eh(m_user_context, this, e, new_bit, phase); + m_decide_eh(m_user_context, this, &e, &new_bit, &phase); enode* new_enode = ctx.get_enode(e); // check if the callback changed something diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index c67a073cd..3f4af0329 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -25,7 +25,7 @@ namespace user_propagator { typedef std::function push_eh_t; typedef std::function pop_eh_t; typedef std::function created_eh_t; - typedef std::function decide_eh_t; + typedef std::function decide_eh_t; class plugin : public decl_plugin { public: From c131eb4db1c03484605c729ec6f6876e4aa5ff2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 16:42:45 +0200 Subject: [PATCH 257/258] build fix --- src/api/c++/z3++.h | 9 +++-- src/opt/maxres.cpp | 96 ++++++++++++++++++++++++++++++++-------------- src/opt/maxsmt.cpp | 6 +++ 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 57a87415d..04e0b78e2 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -4012,12 +4012,13 @@ namespace z3 { p->m_created_eh(e); } - static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast& _val, unsigned& bit, Z3_lbool& is_pos) { + static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast* _val, unsigned* bit, Z3_lbool* is_pos) { user_propagator_base* p = static_cast(_p); scoped_cb _cb(p, cb); - expr val(p->ctx(), _val); - p->m_decide_eh(val, bit, is_pos); - _val = val; + expr val(p->ctx(), *_val); + p->m_decide_eh(val, *bit, *is_pos); + // TBD: life time of val is within the scope of this callback. + *_val = val; } public: diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 4c9964cf4..9fcce1fce 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -72,7 +72,9 @@ class maxres : public maxsmt_solver_base { public: enum strategy_t { s_primal, - s_primal_dual + s_primal_dual, + s_primal_binary, + s_primal_binary_delay }; private: struct stats { @@ -157,6 +159,12 @@ public: case s_primal_dual: m_trace_id = "pd-maxres"; break; + case s_primal_binary: + m_trace_id = "maxres-bin"; + break; + case s_primal_binary_delay: + m_trace_id = "maxres-bin-delay"; + break; } } @@ -357,6 +365,8 @@ public: m_defs.reset(); switch(m_st) { case s_primal: + case s_primal_binary: + case s_primal_binary_delay: return mus_solver(); case s_primal_dual: return primal_dual_solver(); @@ -532,8 +542,18 @@ public: expr_ref fml(m); SASSERT(!core.empty()); TRACE("opt", display_vec(tout << "minimized core: ", core);); - IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); - max_resolve(core, w); + IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); + switch (m_st) { + case strategy_t::s_primal_binary: + bin_max_resolve(core, w); + break; + case strategy_t::s_primal_binary_delay: + bin_delay_max_resolve(core, w); + break; + default: + max_resolve(core, w); + break; + } fml = mk_not(m, mk_and(m, core.size(), core.data())); add(fml); // save small cores such that lex-combinations of maxres can reuse these cores. @@ -700,12 +720,11 @@ public: } } -#if 1 void bin_max_resolve(exprs const& _core, rational const& w) { expr_ref_vector core(m, _core.size(), _core.data()); expr_ref fml(m), cls(m); - for (unsigned i = 0; i + 1 < core.size(); ++i) { + for (unsigned i = 0; i + 1 < core.size(); i += 2) { expr* a = core.get(i); expr* b = core.get(i + 1); expr* u = mk_fresh_bool("u"); @@ -728,36 +747,39 @@ public: s().assert_expr(m.mk_not(core.back())); } -#endif - -#if 0 struct unfold_record { ptr_vector ws; rational weight; }; - void bin_delay_max_resolve(exprs const& _core, rational const& w) { - expr_ref_vector core(m, _core.size(), _core.data()), us(m), partial(m); + obj_map m_unfold; + rational m_unfold_upper; + + void bin_delay_max_resolve(exprs const& _core, rational const& weight) { + expr_ref_vector core(m, _core.size(), _core.data()), partial(m); expr_ref fml(m), cls(m); for (expr* c : core) { - unfold_record ws; - if (!m_unfold.find(c, ws)) + unfold_record r; + if (!m_unfold.find(c, r)) continue; - for (expr* f : ws.ws) - new_assumption(f, ws.weight); + IF_VERBOSE(2, verbose_stream() << "to unfold " << mk_pp(c, m) << "\n"); + for (expr* f : r.ws) { + IF_VERBOSE(2, verbose_stream() << "unfold " << mk_pp(f, m) << "\n"); + new_assumption(f, r.weight); + } + m_unfold_upper -= r.weight * rational(r.ws.size() - 1); + m_unfold.remove(c); } - if (core.size() <= 1) - return; - for (expr* core) + for (expr* _ : core) partial.push_back(nullptr); for (unsigned i = 0; i + 1 < core.size(); ++i) { expr* a = core.get(i); expr* b = core.get(i + 1); - expr_ref u = mk_fresh_bool("u"); - expr_ref v = mk_fresh_bool("v"); + expr* u = mk_fresh_bool("u"); + expr* v = mk_fresh_bool("v"); // u = a or b // v = a and b cls = m.mk_or(a, b); @@ -770,22 +792,28 @@ public: add(fml); update_model(v, cls); m_defs.push_back(fml); - us.push_back(u); core.push_back(v); + // w = u and w1 and w2 unfold_record r; r.ws.push_back(u); if (partial.get(i)) - r.ws.push_back(partia.get(i)); + r.ws.push_back(partial.get(i)); if (partial.get(i + 1)) - r.ws.push_back(partia.get(i + 1)); - partial.push_back(m.mk_and(r.ws)); - m_unfold.insert(partial.back(), r); + r.ws.push_back(partial.get(i + 1)); + m_trail.append(r.ws.size(), r.ws.data()); + w = mk_fresh_bool("w"); + cls = m.mk_and(r.ws); + fml = m.mk_implies(w, cls); + partial.push_back(w); + add(fml); + update_model(w, cls); + m_defs.push_back(fml); + m_unfold.insert(w, r); } - expr_ref u = mk_and(us); - new_assumption(u, w); + new_assumption(w, weight); + s().assert_expr(m.mk_not(core.back())); } -#endif // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { @@ -866,7 +894,7 @@ public: } rational cost(model& mdl) { - rational upper(0); + rational upper = m_unfold_upper; for (soft& s : m_soft) if (!mdl.is_true(s.s)) upper += s.weight; @@ -971,6 +999,8 @@ public: add_upper_bound_block(); m_csmodel = nullptr; m_correction_set_size = 0; + m_unfold.reset(); + m_unfold_upper = 0; return l_true; } @@ -1036,6 +1066,16 @@ opt::maxsmt_solver_base* opt::mk_maxres( return alloc(maxres, c, id, soft, maxres::s_primal); } +opt::maxsmt_solver_base* opt::mk_maxres_binary( + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal_binary); +} + +opt::maxsmt_solver_base* opt::mk_maxres_binary_delay( + maxsat_context& c, unsigned id, vector& soft) { + return alloc(maxres, c, id, soft, maxres::s_primal_binary_delay); +} + opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( maxsat_context& c, unsigned id, vector& soft) { return alloc(maxres, c, id, soft, maxres::s_primal_dual); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index a3d5f2f45..f346a8980 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -191,6 +191,12 @@ namespace opt { else if (m_soft.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { m_msolver = mk_maxres(m_c, m_index, m_soft); } + else if (maxsat_engine == symbol("maxres-bin")) { + m_msolver = mk_maxres_binary(m_c, m_index, m_soft); + } + else if (maxsat_engine == symbol("maxres-bin-delay")) { + m_msolver = mk_maxres_binary_delay(m_c, m_index, m_soft); + } else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_soft); } From b5309d5fd073c1e056b3ce436c393b28e13afe10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Apr 2022 16:42:57 +0200 Subject: [PATCH 258/258] na --- src/opt/maxres.cpp | 10 ++++++++-- src/opt/maxres.h | 4 ++++ src/opt/opt_params.pyg | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 9fcce1fce..10ab3c77b 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -774,8 +774,14 @@ public: for (expr* _ : core) partial.push_back(nullptr); - - for (unsigned i = 0; i + 1 < core.size(); ++i) { + + std::cout << "Core size " << core.size() << "\n"; + + if (core.size() > 2) + m_unfold_upper += rational(core.size()-2)*weight; + + expr* w = nullptr; + for (unsigned i = 0; i + 1 < core.size(); i += 2) { expr* a = core.get(i); expr* b = core.get(i + 1); expr* u = mk_fresh_bool("u"); diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 25ef9bf05..947b60492 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -23,6 +23,10 @@ namespace opt { maxsmt_solver_base* mk_maxres(maxsat_context& c, unsigned id, vector& soft); + maxsmt_solver_base* mk_maxres_binary(maxsat_context& c, unsigned id, vector& soft); + + maxsmt_solver_base* mk_maxres_binary_delay(maxsat_context& c, unsigned id, vector& soft); + maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector& soft); }; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 5106c5492..cb8f1d129 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'maxres-bin-delay'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('dump_models', BOOL, False, 'display intermediary models to stdout'),